Compare commits

..

100 Commits

Author SHA1 Message Date
Safihre
4917885ea1 Simplify black formatting validation step 2026-02-10 13:22:45 +01:00
mnightingale
8c7a70b6c4 Add socket for read/write if next request or partial write (#3313)
* Add for read/write if next request or partial write

* Refactor to also call on partial write but no full response path and add comments
2026-02-10 10:18:10 +01:00
mnightingale
7f8d7d80d2 Make conditional_cache exception safe and exclude force from the key (#3317) 2026-02-09 21:27:15 +01:00
SABnzbd Automation
40ea82a8bb Update translatable texts
[skip ci]
2026-02-09 15:45:29 +00:00
Safihre
2122503762 Update copyright to 2026 2026-02-09 16:44:38 +01:00
mnightingale
507edc3ddf Revert allow_new_fetcher for stuck jobs (#3314) 2026-02-09 09:07:14 +01:00
renovate[bot]
920e23e11e Update dependency setuptools to v82 (#3315)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-09 02:20:51 +00:00
SABnzbd Automation
e898f92f49 Update translatable texts
[skip ci]
2026-02-08 15:26:45 +00:00
mnightingale
9a37306ce5 Only increment next index if expected (#3312) 2026-02-08 16:26:03 +01:00
mnightingale
47e71912d5 Ignore all OSError from FakeNNTPServer (#3309) 2026-02-06 18:18:18 +01:00
mnightingale
b90be6e35a Allow new fetcher for stuck articles (#3308) 2026-02-06 18:17:32 +01:00
mnightingale
4e7a70c5e7 Fix server retention not always applied (#3304)
* Fix server retention not always applied

* Comment why safe to discard remaining queue and not check retention for each
2026-02-06 13:04:16 +01:00
Safihre
9fc2215fc8 Skip orjson on Python 3.9 2026-02-06 12:01:31 +01:00
Safihre
cba63c0c3e No longer specify cryptography version
To support win_arm64 again
See https://github.com/pyca/cryptography/pull/14216
2026-02-06 12:01:30 +01:00
renovate[bot]
2b62846122 Update all dependencies 2026-02-05 19:13:22 +00:00
thezoggy
cb5030d152 bump mac to build with python 3.14.3 (#3307) 2026-02-05 20:12:49 +01:00
thezoggy
499e9639e9 unrar 7.20 (#3306) 2026-02-05 20:12:23 +01:00
Safihre
e1ea4f1e7e Update text files for 5.0.0Beta1 2026-02-02 15:26:00 +01:00
mnightingale
e40098d0e7 Remove sleep when cache is full (#3300)
* Remove cache full sleep

* Remove override_trigger
2026-02-02 10:27:48 +01:00
SABnzbd Automation
5025f9ec5d Update translatable texts
[skip ci]
2026-02-02 08:15:36 +00:00
mnightingale
26a485374c Only wake servers while requests are available (#3299) 2026-02-02 09:14:54 +01:00
mnightingale
5b3a8fcd3f Fix nzb deadlocks (#3298)
* Fix nzb deadlocks

* Keep the lock behaviour unchanged but ensure correct order
2026-01-30 17:23:57 +01:00
mnightingale
44447ab416 Add more logging to stop_idle_jobs (#3294)
* Add more logging to stop_idle_jobs

* Would log too much

* Reduce logging a little

* Tweak message

* Spelling

* Log first articles
2026-01-30 15:24:52 +01:00
mnightingale
040573c75c Fix deadlock in hard_reset/remove_socket (#3297) 2026-01-29 18:14:22 +01:00
mnightingale
16a6936053 Bind socket throughout test but don't listen and configure a timeout (#3296) 2026-01-29 12:07:27 +01:00
mnightingale
e2921e7b9c Add guards to process_nw_read (#3295) 2026-01-29 08:10:12 +01:00
mnightingale
e1cd1eed83 Remove unused logging arguments (#3293) 2026-01-27 20:35:23 +01:00
SABnzbd Automation
a4de704967 Update translatable texts
[skip ci]
2026-01-26 18:07:10 +00:00
mnightingale
d9f9aa5bea Fix adding sockets mid-connect (#3291)
* Do not add sockets that are not already connected

* Don't preemptively mark thread busy

* Clear nntp instance on failed connect

* Just use reset_nw like everywhere else

* Track when the socket is connected and idle connections can handle requested when connected (completed auth) or socket_connected

* Add tests for connection state handling

* Windows is really slow at this

* Rename connected to ready and socket_connected to connected
2026-01-26 19:06:22 +01:00
renovate[bot]
f4b73cf9ec Update all dependencies (#3292)
* Update all dependencies

* pycparser dropped support for Python 3.9

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Safihre <safihre@sabnzbd.org>
2026-01-26 11:09:39 +01:00
SABnzbd Automation
ddc84542eb Update translatable texts
[skip ci]
2026-01-26 09:50:06 +00:00
Safihre
9624a285f1 Add Apprise documentation URL to Notifications page 2026-01-26 10:45:11 +01:00
Safihre
43a9678f07 Do not show tracebacks externally
Releastes to #3286
2026-01-23 13:36:46 +01:00
mnightingale
4ee41e331c Handle SSLWantWriteError exceptions and buffer writes (#3289)
* Handle SSLWantWriteError

* Add buffer for non-blocking writes
2026-01-23 09:21:32 +01:00
mnightingale
062dc9fa11 Fix assembler waiting for failed article (#3290) 2026-01-23 07:12:16 +01:00
SABnzbd Automation
d215d4b0d7 Update translatable texts
[skip ci]
2026-01-21 20:44:06 +00:00
Safihre
04711886d9 Bump next release from 4.6 to 5.0 due to major changes
No release yet, just text bumps
2026-01-21 21:42:59 +01:00
mnightingale
a19b3750e3 Handle non-fatal errors during read (#3280)
* Handle non-fatal errors during read

* sabctools 9.3.1
2026-01-21 21:18:58 +01:00
mnightingale
eff5f663ab Add database indexes (#3283)
* Add database indexes

* Remove completed bytes index

* Allow duplicate query to short circuit

* Remove duplicate indexes

* Remove most of the query changes
2026-01-20 11:52:49 +01:00
mnightingale
46c98acff3 Fix inconsistent NzbFile sorting (#3276)
* Fix inconsistent NzbFile sorting

* Add more groups and tiers

* Black formatting
2026-01-20 11:06:02 +01:00
renovate[bot]
df5fad29bc Update all dependencies (#3285)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-19 13:04:31 +01:00
SABnzbd Automation
27d222943c Update translatable texts
[skip ci]
2026-01-19 11:43:49 +00:00
Safihre
3384beed24 Make black 26.1.0 happy again - almost 2026-01-19 12:42:51 +01:00
mnightingale
bf41237135 Trigger assemble when next is available and it has been 5 seconds (#3281) 2026-01-17 09:53:06 +01:00
mnightingale
3d4fabfbdf Log socket exception type on write error (#3279) 2026-01-16 22:08:16 +01:00
mnightingale
cf14e24036 Revert pipelining stat/head check (#3278) 2026-01-15 21:12:20 +01:00
Safihre
d0c2b74181 Add current version/environment metadata to _api_showlog
Closes #3277
2026-01-15 10:02:34 +01:00
mnightingale
d21a111993 Fix pipelining connection read/write logic errors (#3272)
* Fix commands which fail to be sent are lost

* Force macOS to use the select implementation

* Do not recreate lock when reinitialised

* Suppress errors when closing socket to ensure socket is closed

* Make connection errors on read or write both only wait 5 seconds before reconnecting

* Fix selector selection

* Only check generation under lock

* Use PollSelector
2026-01-12 15:19:07 +01:00
mnightingale
3e7dcce365 Fix queue cannot be loaded (#3271)
* Fix queue cannot be restored

* Also change init

* Add a test

Fixes #3269
2026-01-12 09:54:59 +01:00
renovate[bot]
5594d4d6eb Update dependency urllib3 to v2.6.3 (#3274)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-12 01:34:09 +00:00
SABnzbd Automation
605a1b30be Update translatable texts
[skip ci]
2026-01-11 21:42:10 +00:00
mnightingale
a2cb861640 Fix bug when bandwidth limit is removed (#3273) 2026-01-11 22:41:27 +01:00
mnightingale
df1c0915d0 Recreate frènch_german_demö test data (#3268) 2026-01-09 10:59:51 +01:00
mnightingale
4d73c3e9c0 Adjust monitored socket events as required to prevent hot looping (#3267)
* Adjust monitored socket events as required to prevent hot looping

* Prevent write hot looping

* Guard against pending recursive call

* Already have EVENT_READ and don't need to handle it in two places
2026-01-08 15:14:59 +01:00
Safihre
17dcff49b2 Generalize locking strategy (#3264)
* Use per-nzo/nzf lock in wrapper

* Replace global TryList lock with per-nzo one

* Offset does require file_lock
2026-01-06 17:00:27 +01:00
mnightingale
220186299b Do not throttle flushing cache during shutdown (#3265)
* Add a deadline for flushing cache contents on shutdown and don't throttle

* Revert "Add a deadline for flushing cache contents on shutdown and don't throttle"

This reverts commit e405b4c4f4.

* Always flush the whole cache but don't sleep when shutting down
2026-01-06 16:58:39 +01:00
Safihre
ae30be382b Merge platform specific memory functions into single 2026-01-06 13:38:06 +01:00
SABnzbd Automation
13b10fd9bb Update translatable texts
[skip ci]
2026-01-06 11:46:06 +00:00
mnightingale
d9bb544caf Always enqueue when file_done (#3263) 2026-01-06 12:45:25 +01:00
SABnzbd Automation
bf2080068c Update translatable texts
[skip ci]
2026-01-06 09:03:40 +00:00
mnightingale
b4e8c80bc9 Implement Direct Write (#3236)
* Implement direct write

* Support direct_write changes at runtime

* Check sparse support when download_dir changes

* Fixes to reverting to append mode and add tests

* Single write path, remove truncate, improve tests, add test for append mode with out of order direct writes

* assert expected nzf.assembler_next_index

* bytes_written_sequentially assertions

* Slim tests and mock load_article as a dictionary

* More robust bytes_written_sequentially

* Worked but guard Python -1 semantics

* os.path.getsize silly

* Add test with force followed by append to gaps

* Split flush_cache into its own function so the loop does not need to clear the article variable

* Fewer private functions

* Extract article cache limit for waiting constant

* Move option back to specials

* Use Status.DELETED for clarity

* Use nzo.lock in articlecache

* Document why assembler_next_index increments

* Remove duplicated code from write

* load_data formatting

* Create files with the same permissions as with open(...)

* Options are callable

* Fix crash if direct writing from cache but has been deleted

* Fix crash in next_index check via article cache

* Fix assembler waiting for register_article and cache waiting for assembler to write

* Simplify flush_cache loop and only log once per second

* Document why we would leave the assembler when forced at the first not tried article

* When skippedwe can't increment the next_index

* Rename bytes_written_sequentially to sequential_offset improve comments and logic

* Don't need to check when the config changes, due to the runtime changes any failure during assembly will disable it

* Remove unused constant

* Improve append triggering based on contiguous bytes ready to write to file and add a trigger to direct write

* Throttle downloader threads when direct writing out of order

* Clear ready_bytes when removed from queue

* Rework check_assembler_levels sleeping to have a deadline, be based on if the assembler actual pending bytes, and if delaying could have any impact

* Always write first articles if filenames are checked

* Rename force to allow_non_contiguous so it is clearer what it means

* Article is required

* Tweak delay triggers

* Fix for possible dictionary changed size during iteration

* postproc only gets the nzo

* Rename constants and remove redundant calculation

* For safety just key by nzf_id

* Not redundant because capped at 500M

* Tweak a little more

* Only delay if assembler is busy

* Remove unused constant and rename the remaining one

* Calculate if direct write is allowed when cache limit changes

* Allow direct writes to bypass trigger

* Avoid race to requeue

* Breakup the queuing logic so its understandable
2026-01-06 10:03:00 +01:00
Safihre
33aa4f1199 Revert "OptionBool should return bool"
This reverts commit ecb36442d3.

It messes up the sabnzbd.ini reading/writing!
2026-01-05 15:58:54 +01:00
Safihre
ecb36442d3 OptionBool should return bool
Hmm why wasn't this the case?
2026-01-05 14:50:35 +01:00
Safihre
0bbe34242e Stop updating uvicorn branch 2026-01-05 09:51:55 +01:00
renovate[bot]
7c6abd9528 Update all dependencies (#3258)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-05 01:53:32 +00:00
Safihre
448c034f79 Simplify get_windows_memory 2026-01-03 22:03:26 +01:00
mnightingale
9d5cf9fc5b Fix binding outgoing ip test when ipv6 is available (#3257) 2026-01-02 15:53:48 +01:00
mnightingale
4f9d0fb7d4 Fix connection test failing when bad credentials are used (#3256) 2026-01-02 15:03:04 +01:00
mnightingale
240d5b4ff7 Fix failing downloader tests and make tests less fragile (#3254)
* Fix failing downloader tests and make tests less fragile

* Implement feedback

* Spelling and only sleep if necessary

* Grammar is hard
2026-01-02 15:02:34 +01:00
SABnzbd Automation
a2161ba89b Update translatable texts
[skip ci]
2026-01-02 11:50:29 +00:00
Safihre
68e193bf56 Use blocking writes instead of buffering (#3248) 2026-01-02 12:49:42 +01:00
SABnzbd Automation
b5dda7c52d Update translatable texts
[skip ci]
2025-12-30 08:24:04 +00:00
mnightingale
b6691003db Refactor RSS flow (#3247) 2025-12-30 09:23:20 +01:00
Safihre
ed655553c8 Pausing the queue with Force'd downloads doesn't let them download
Closes #3246
2025-12-29 12:37:44 +01:00
Safihre
316b96c653 Add context folder with documents for AI-tools 2025-12-29 12:12:58 +01:00
mnightingale
62401cba27 Simplify RSS rule evaluation (#3243) 2025-12-29 10:50:55 +01:00
renovate[bot]
3cabf44ce3 Update dependency pyinstaller-hooks-contrib to v2025.11 (#3244)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-29 08:55:14 +01:00
mnightingale
a637d218c4 Refactor preparing the rss config (#3242)
* Refactor preparing the rss config

* Defaults, bool, and iteration
2025-12-24 21:47:15 +01:00
Safihre
63c03b42a9 Update text files for 4.6.0Beta2 2025-12-22 22:00:02 +01:00
SABnzbd Automation
4539837fad Update translatable texts
[skip ci]
2025-12-22 20:53:43 +00:00
Safihre
a0cd48e3f5 Notify user if they run AMD64 version on ARM64 Windows machine
Closes #3235
2025-12-22 21:52:58 +01:00
Safihre
ceeb7cb162 Add Windows ARM64 binary 2025-12-22 21:25:17 +01:00
SABnzbd Automation
f9f4e1b028 Update translatable texts
[skip ci]
2025-12-22 15:40:48 +00:00
Safihre
6487944c6c Move Pipelining setting to Server-level 2025-12-22 16:38:46 +01:00
renovate[bot]
239fddf39c Update all dependencies (develop) (#3238)
* Update all dependencies

* Compare fakefs result after sorting

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Safihre <safihre@sabnzbd.org>
2025-12-22 12:45:00 +00:00
SABnzbd Automation
8ada8b2fd9 Update translatable texts
[skip ci]
2025-12-19 11:41:18 +00:00
Safihre
b19bd65495 Show error in case of failed NZB upload
Closes #3233
2025-12-19 12:40:34 +01:00
Safihre
e3ea5fdd64 Update appdata file with Flathub suggestions
@jcfp
2025-12-19 11:54:53 +01:00
Safihre
4fdb89701a Add release URL's to appdata 2025-12-19 11:42:36 +01:00
SABnzbd Automation
9165c4f304 Update translatable texts
[skip ci]
2025-12-18 20:10:14 +00:00
mnightingale
4152f0ba6a Increase max pipelining (#3234) 2025-12-18 20:09:24 +00:00
SABnzbd Automation
3eaab17739 Update translatable texts
[skip ci]
2025-12-16 09:04:29 +00:00
Safihre
578bfd083d Update text files 4.6.0 Beta 1 2025-12-16 10:03:41 +01:00
renovate[bot]
dd464456e4 Update all dependencies (#3231)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-15 02:08:17 +00:00
mnightingale
e7a0255359 Make behaviour after reset more robust (#3229)
* Make behaviour after reset more robust

* Remove use of hasattr and rename to generation

* I had a feeling this would be a circular reference

* Reset and increment generation under lock
2025-12-14 22:39:48 +01:00
mnightingale
2e1281d9e8 Fix nzb types (#3230) 2025-12-14 15:46:14 +01:00
SABnzbd Automation
efecefdd3b Update translatable texts
[skip ci]
2025-12-09 20:22:55 +00:00
Safihre
a91e718ef5 Split nzbstuff into separate files for Article, NzbFile and NzbObject (#3221) 2025-12-09 21:21:51 +01:00
mnightingale
b420975267 Fix read/write actions after reset_nw (#3223) 2025-12-09 19:39:49 +01:00
SABnzbd Automation
c4211df8dc Update translatable texts
[skip ci]
2025-12-08 21:37:36 +00:00
193 changed files with 5326 additions and 3975 deletions

View File

@@ -7,7 +7,7 @@
"schedule": [
"before 8am on Monday"
],
"baseBranches": ["develop", "feature/uvicorn"],
"baseBranches": ["develop"],
"pip_requirements": {
"fileMatch": [
"requirements.txt",

View File

@@ -8,8 +8,18 @@ env:
jobs:
build_windows:
name: Build Windows binary
runs-on: windows-2022
name: Build Windows binary (${{ matrix.architecture }})
strategy:
fail-fast: false
matrix:
include:
- architecture: x64
runs-on: windows-2022
- architecture: arm64
runs-on: windows-11-arm
runs-on: ${{ matrix.runs-on }}
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
@@ -17,25 +27,26 @@ jobs:
uses: actions/setup-python@v6
with:
python-version: "3.14"
architecture: "x64"
architecture: ${{ matrix.architecture }}
cache: pip
cache-dependency-path: "**/requirements.txt"
- name: Install Python dependencies
# Without dependencies to make sure everything is covered in the requirements.txt
# Special cryptography is due to https://github.com/pyca/cryptography/pull/14216
run: |
python --version
python -m pip install --upgrade pip wheel
pip install --upgrade -r requirements.txt --no-dependencies
pip install --upgrade -r requirements.txt --no-dependencies --only-binary=cryptography
pip install --upgrade -r builder/requirements.txt --no-dependencies
- name: Build Windows standalone binary
id: windows_binary
run: python builder/package.py binary
- name: Upload Windows standalone binary (unsigned)
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
id: upload-unsigned-binary
with:
path: "*-win64-bin.zip"
name: Windows standalone binary
path: "*-win*-bin.zip"
name: Windows standalone binary (${{ matrix.architecture }})
- name: Sign Windows standalone binary
uses: signpath/github-action-submit-signing-request@v2
if: contains(github.ref, 'refs/tags/')
@@ -49,22 +60,24 @@ jobs:
wait-for-completion: true
output-artifact-directory: "signed"
- name: Upload Windows standalone binary (signed)
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
if: contains(github.ref, 'refs/tags/')
with:
name: Windows standalone binary (signed)
name: Windows standalone binary (${{ matrix.architecture }}, signed)
path: "signed"
- name: Build Windows installer
if: matrix.architecture == 'x64'
run: python builder/package.py installer
- name: Upload Windows installer
uses: actions/upload-artifact@v5
if: matrix.architecture == 'x64'
uses: actions/upload-artifact@v6
id: upload-unsigned-installer
with:
path: "*-win-setup.exe"
name: Windows installer
name: Windows installer (${{ matrix.architecture }})
- name: Sign Windows installer
if: matrix.architecture == 'x64' && contains(github.ref, 'refs/tags/')
uses: signpath/github-action-submit-signing-request@v2
if: contains(github.ref, 'refs/tags/')
with:
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
organization-id: ${{ secrets.SIGNPATH_ORG_ID }}
@@ -75,10 +88,10 @@ jobs:
wait-for-completion: true
output-artifact-directory: "signed"
- name: Upload Windows installer (signed)
if: contains(github.ref, 'refs/tags/')
uses: actions/upload-artifact@v5
if: matrix.architecture == 'x64' && contains(github.ref, 'refs/tags/')
uses: actions/upload-artifact@v6
with:
name: Windows installer (signed)
name: Windows installer (${{ matrix.architecture }}, signed)
path: "signed/*-win-setup.exe"
build_macos:
@@ -89,7 +102,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.14.2"
PYTHON_VERSION: "3.14.3"
MACOSX_DEPLOYMENT_TARGET: "10.15"
# We need to force compile for universal2 support
CFLAGS: -arch x86_64 -arch arm64
@@ -105,7 +118,7 @@ jobs:
cache-dependency-path: "**/requirements.txt"
- name: Cache Python download
id: cache-python-download
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ~/python.pkg
key: cache-macOS-Python-${{ env.PYTHON_VERSION }}
@@ -140,7 +153,7 @@ jobs:
# Run this on macOS so the line endings are correct by default
run: python builder/package.py source
- name: Upload source distribution
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
path: "*-src.tar.gz"
name: Source distribution
@@ -153,7 +166,7 @@ jobs:
python3 builder/package.py app
python3 builder/make_dmg.py
- name: Upload macOS binary
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
path: "*-macos.dmg"
name: macOS binary
@@ -167,14 +180,14 @@ jobs:
matrix:
include:
- os: ubuntu-latest
linux_arch: amd64
linux_arch: x64
- os: ubuntu-24.04-arm
linux_arch: arm64
steps:
- uses: actions/checkout@v6
- name: Cache par2cmdline-turbo tarball
uses: actions/cache@v4
uses: actions/cache@v5
id: cache-par2cmdline
# Clearing the cache in case of new version requires manual clearing in GitHub!
with:
@@ -196,7 +209,7 @@ jobs:
timeout 10s snap run sabnzbd --help || true
sudo snap remove sabnzbd
- name: Upload snap
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
name: Snap package (${{ matrix.linux_arch }})
path: ${{ steps.snapcraft.outputs.snap }}
@@ -223,15 +236,15 @@ jobs:
cache: pip
cache-dependency-path: "builder/release-requirements.txt"
- name: Download Source distribution artifact
uses: actions/download-artifact@v6
uses: actions/download-artifact@v7
with:
name: Source distribution
- name: Download macOS artifact
uses: actions/download-artifact@v6
uses: actions/download-artifact@v7
with:
name: macOS binary
- name: Download Windows artifacts
uses: actions/download-artifact@v6
uses: actions/download-artifact@v7
with:
pattern: ${{ (contains(github.ref, 'refs/tags/')) && '*signed*' || '*Windows*' }}
merge-multiple: true

View File

@@ -8,21 +8,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Black Code Formatter
uses: lgeiger/black-action@master
with:
args: >
SABnzbd.py
sabnzbd
scripts
tools
builder
builder/SABnzbd.spec
tests
--line-length=120
--target-version=py39
--check
--diff
- run: pip install black
# Tools folder excluded for now due to https://github.com/psf/black/issues/4963
- run: >
black
SABnzbd.py
sabnzbd
scripts
builder
builder/SABnzbd.spec
tests
--line-length=120
--target-version=py39
--check
--diff
test:
name: Test ${{ matrix.name }} - Python ${{ matrix.python-version }}

View File

@@ -26,7 +26,7 @@ jobs:
if: github.repository_owner == 'sabnzbd'
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5
- uses: dessant/lock-threads@v6
with:
log-output: true
issue-inactive-days: 60

View File

@@ -30,7 +30,7 @@ jobs:
run: |
python3 tools/make_mo.py
- name: Push translatable and translated texts back to repo
uses: stefanzweifel/git-auto-commit-action@v7.0.0
uses: stefanzweifel/git-auto-commit-action@v7.1.0
if: env.TX_TOKEN
with:
commit_message: |

View File

@@ -1,5 +1,5 @@
(c) Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
(c) Copyright 2007-2026 by The SABnzbd-Team (sabnzbd.org)
The SABnzbd-Team is:

View File

@@ -4,7 +4,7 @@
0) LICENSE
-------------------------------------------------------------------------------
(c) Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
(c) Copyright 2007-2026 by 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

View File

@@ -1,4 +1,4 @@
(c) Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
(c) Copyright 2007-2026 by 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

View File

@@ -1,27 +1,36 @@
Release Notes - SABnzbd 4.6.0 Alpha 2
Release Notes - SABnzbd 5.0.0 Beta 1
=========================================================
This is the second test release of version 4.6.
This is the first beta release of version 5.0.
## New features in 4.6.0
Due to several fundamental changes we decided to
not just call this 4.6 but promote it to 5.0!
* Added default support for NNTP Pipelining which eliminates idle waiting
between requests, significantly improving speeds on high-latency connections.
## New features in 5.0.0
* Added support for NNTP Pipelining which eliminates idle waiting between
requests, significantly improving speeds on high-latency connections.
Read more here: https://sabnzbd.org/wiki/advanced/nntp-pipelining
* Dynamically increase Assembler limits on faster connections.
* Implemented Direct Write to optimize assembly of downloaded files.
Read more here: https://sabnzbd.org/wiki/advanced/direct-write
* Complete redesign of article cache.
* Improved disk speed measurement in Status window.
* Enable `verify_xff_header` by default.
* Reduce delays between jobs during post-processing.
* If a download only has `.nzb` files inside, the new downloads
will include the name of the original download.
* No longer show tracebacks in the browser, only in the logs.
* Dropped support for Python 3.8.
* Windows: Added Windows ARM (portable) release.
## Bug fixes since 4.5.0
* `Check before download` could get stuck or fail to reject.
* Windows: Tray icon disappears after Explorer restart.
* No error was shown in case NZB upload failed.
* Correct mobile layout if `Full Width` is enabled.
* Aborted Direct Unpack could result in no files being unpacked.
* Sorting of files inside jobs was inconsistent.
* Windows: Tray icon disappears after Explorer restart.
* macOS: Slow to start on some network setups.
@@ -47,4 +56,4 @@ It simplifies the process of downloading from Usenet dramatically, thanks to its
user interface and advanced built-in post-processing options that automatically verify, repair,
extract and clean up posts downloaded from Usenet.
(c) Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
(c) Copyright 2007-2026 by The SABnzbd-Team (sabnzbd.org)

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -236,21 +236,16 @@ def print_help():
def print_version():
print(
(
"""
print(("""
%s-%s
(C) Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
(C) Copyright 2007-2026 by The SABnzbd-Team (sabnzbd.org)
SABnzbd comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions. It is licensed under the
GNU GENERAL PUBLIC LICENSE Version 2 or (at your option) any later version.
"""
% (sabnzbd.MY_NAME, sabnzbd.__version__)
)
)
""" % (sabnzbd.MY_NAME, sabnzbd.__version__)))
def daemonize():
@@ -870,7 +865,7 @@ def main():
elif opt in ("-t", "--templates"):
web_dir = arg
elif opt in ("-s", "--server"):
(web_host, web_port) = split_host(arg)
web_host, web_port = split_host(arg)
elif opt in ("-n", "--nobrowser"):
autobrowser = False
elif opt in ("-b", "--browser"):
@@ -1280,7 +1275,6 @@ def main():
"tools.encode.on": True,
"tools.gzip.on": True,
"tools.gzip.mime_types": mime_gzip,
"request.show_tracebacks": True,
"error_page.401": sabnzbd.panic.error_page_401,
"error_page.404": sabnzbd.panic.error_page_404,
}

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2008-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2008-2026 by 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
@@ -16,6 +16,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import os
import platform
import re
# Constants
@@ -43,11 +44,17 @@ RELEASE_VERSION_BASE = f"{RELEASE_VERSION_TUPLE[0]}.{RELEASE_VERSION_TUPLE[1]}.{
RELEASE_NAME = "SABnzbd-%s" % RELEASE_VERSION
RELEASE_TITLE = "SABnzbd %s" % RELEASE_VERSION
RELEASE_SRC = RELEASE_NAME + "-src.tar.gz"
RELEASE_BINARY = RELEASE_NAME + "-win64-bin.zip"
RELEASE_INSTALLER = RELEASE_NAME + "-win-setup.exe"
RELEASE_WIN_BIN_X64 = RELEASE_NAME + "-win64-bin.zip"
RELEASE_WIN_BIN_ARM64 = RELEASE_NAME + "-win-arm64-bin.zip"
RELEASE_WIN_INSTALLER = RELEASE_NAME + "-win-setup.exe"
RELEASE_MACOS = RELEASE_NAME + "-macos.dmg"
RELEASE_README = "README.mkd"
# Detect architecture
RELEASE_WIN_BIN = RELEASE_WIN_BIN_X64
if platform.machine() == "ARM64":
RELEASE_WIN_BIN = RELEASE_WIN_BIN_ARM64
# Used in package.py and SABnzbd.spec
EXTRA_FILES = [
RELEASE_README,

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2008-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2008-2026 by 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
@@ -18,7 +18,6 @@
import os
from constants import RELEASE_VERSION
# We need to call dmgbuild from command-line, so here we can setup how
if __name__ == "__main__":
# Check for DMGBuild

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2008-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2008-2026 by 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
@@ -35,8 +35,8 @@ from constants import (
VERSION_FILE,
RELEASE_README,
RELEASE_NAME,
RELEASE_BINARY,
RELEASE_INSTALLER,
RELEASE_WIN_BIN,
RELEASE_WIN_INSTALLER,
ON_GITHUB_ACTIONS,
RELEASE_THIS,
RELEASE_SRC,
@@ -257,7 +257,7 @@ if __name__ == "__main__":
# Remove any leftovers
safe_remove(RELEASE_NAME)
safe_remove(RELEASE_BINARY)
safe_remove(RELEASE_WIN_BIN)
# Run PyInstaller and check output
shutil.copyfile("builder/SABnzbd.spec", "SABnzbd.spec")
@@ -275,8 +275,8 @@ if __name__ == "__main__":
test_sab_binary("dist/SABnzbd/SABnzbd.exe")
# Create the archive
run_external_command(["win/7zip/7za.exe", "a", RELEASE_BINARY, "SABnzbd"], cwd="dist")
shutil.move(f"dist/{RELEASE_BINARY}", RELEASE_BINARY)
run_external_command(["win/7zip/7za.exe", "a", RELEASE_WIN_BIN, "SABnzbd"], cwd="dist")
shutil.move(f"dist/{RELEASE_WIN_BIN}", RELEASE_WIN_BIN)
if "installer" in sys.argv:
# Check if we have the dist folder
@@ -284,10 +284,10 @@ if __name__ == "__main__":
raise FileNotFoundError("SABnzbd executable not found, run binary creation first")
# Check if we have a signed version
if os.path.exists(f"signed/{RELEASE_BINARY}"):
if os.path.exists(f"signed/{RELEASE_WIN_BIN}"):
print("Using signed version of SABnzbd binaries")
safe_remove("dist/SABnzbd")
run_external_command(["win/7zip/7za.exe", "x", "-odist", f"signed/{RELEASE_BINARY}"])
run_external_command(["win/7zip/7za.exe", "x", "-odist", f"signed/{RELEASE_WIN_BIN}"])
# Make sure it exists
if not os.path.exists("dist/SABnzbd/SABnzbd.exe"):
@@ -310,7 +310,7 @@ if __name__ == "__main__":
"/V3",
"/DSAB_VERSION=%s" % RELEASE_VERSION,
"/DSAB_VERSIONKEY=%s" % ".".join(map(str, RELEASE_VERSION_TUPLE)),
"/DSAB_FILE=%s" % RELEASE_INSTALLER,
"/DSAB_FILE=%s" % RELEASE_WIN_INSTALLER,
"NSIS_Installer.nsi.tmp",
]
)

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2008-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2008-2026 by 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
@@ -29,8 +29,9 @@ from constants import (
RELEASE_VERSION_BASE,
PRERELEASE,
RELEASE_SRC,
RELEASE_BINARY,
RELEASE_INSTALLER,
RELEASE_WIN_BIN_X64,
RELEASE_WIN_BIN_ARM64,
RELEASE_WIN_INSTALLER,
RELEASE_MACOS,
RELEASE_README,
RELEASE_THIS,
@@ -42,8 +43,9 @@ from constants import (
# Verify we have all assets
files_to_check = (
RELEASE_SRC,
RELEASE_BINARY,
RELEASE_INSTALLER,
RELEASE_WIN_BIN_X64,
RELEASE_WIN_BIN_ARM64,
RELEASE_WIN_INSTALLER,
RELEASE_MACOS,
RELEASE_README,
)

View File

@@ -1,19 +1,19 @@
# Basic build requirements
# Note that not all sub-dependencies are listed, but only ones we know could cause trouble
pyinstaller==6.17.0
packaging==25.0
pyinstaller-hooks-contrib==2025.10
pyinstaller==6.18.0
packaging==26.0
pyinstaller-hooks-contrib==2026.0
altgraph==0.17.5
wrapt==2.0.1
setuptools==80.9.0
wrapt==2.1.1
setuptools==82.0.0
# For the Windows build
pefile==2024.8.26; sys_platform == 'win32'
pywin32-ctypes==0.2.3; sys_platform == 'win32'
# For the macOS build
dmgbuild==1.6.6; sys_platform == 'darwin'
dmgbuild==1.6.7; sys_platform == 'darwin'
mac-alias==2.2.3; sys_platform == 'darwin'
macholib==1.16.4; sys_platform == 'darwin'
ds-store==1.3.2; sys_platform == 'darwin'
PyNaCl==1.6.1; sys_platform == 'darwin'
PyNaCl==1.6.2; sys_platform == 'darwin'

39
context/Download-flow.md Normal file
View File

@@ -0,0 +1,39 @@
## Download flow (Downloader + NewsWrapper)
1. **Job ingestion**
- NZBs arrive via UI/API/URL; `urlgrabber.py` fetches remote NZBs, `nzbparser.py` turns them into `NzbObject`s, and `nzbqueue.NzbQueue` stores ordered jobs with priorities and categories.
2. **Queue to articles**
- When servers need work, `NzbQueue.get_articles` (called from `Server.get_article` in `downloader.py`) hands out batches of `Article`s per server, respecting retention, priority, and forced/paused items.
3. **Downloader setup**
- `Downloader` thread loads server configs (`config.get_servers`), instantiates `Server` objects (per host/port/SSL/threads), and spawns `NewsWrapper` instances per configured connection.
- A `selectors.DefaultSelector` watches all sockets; `BPSMeter` tracks throughput and speed limits; timers manage server penalties/restarts.
4. **Connection establishment (NewsWrapper.init_connect → NNTP.connect)**
- `Server.request_addrinfo` resolves fastest address; `NewsWrapper` builds an `NNTP` socket, wraps SSL if needed, sets non-blocking, and registers with the selector.
- First server greeting (200/201) is queued; `finish_connect` drives the login handshake (`AUTHINFO USER/PASS`) and handles temporary (480) or permanent (400/502) errors.
5. **Request scheduling & pipelining**
- `write()` chooses the next article command (`STAT/HEAD` for precheck, `BODY` or `ARTICLE` otherwise).
- Concurrency is limited by `server.pipelining_requests`; commands are queued and sent with `sock.sendall`, so there is no local send buffer.
- Sockets stay registered for `EVENT_WRITE`: without write readiness events, a temporarily full kernel send buffer could stall queued commands when there is nothing to read, so WRITE interest is needed to resume sending promptly.
6. **Receiving data**
- Selector events route to `process_nw_read`; `NewsWrapper.read` pulls bytes (SSL optimized via sabctools), parses NNTP responses, and calls `on_response`.
- Successful BODY/ARTICLE (220/222) updates per-server stats; missing/500 variants toggle capability flags (BODY/STAT support).
7. **Decoding and caching**
- `Downloader.decode` hands responses to `decoder.decode`, which yEnc/UU decodes, CRC-checks, and stores payloads in `ArticleCache` (memory or disk spill).
- Articles with DMCA/bad data trigger retry on other servers until `max_art_tries` is exceeded.
8. **Assembly to files**
- `Assembler` worker consumes decoded pieces, writes to the target file, updates CRC, and cleans admin markers. It guards disk space (`diskspace_check`) and schedules direct unpack or PAR2 handling when files finish.
9. **Queue bookkeeping**
- `NzbQueue.register_article` records success/failure; completed files advance NZF/NZO state. If all files done, the job moves to post-processing (`PostProcessor.process`), which runs `newsunpack`, scripts, sorting, etc.
10. **Control & resilience**
- Pausing/resuming (`Downloader.pause/resume`), bandwidth limiting, and sleep tuning happen in the main loop.
- Errors/timeouts lead to `reset_nw` (close socket, return article, maybe penalize server). Optional servers can be temporarily disabled; required ones schedule resumes.
- Forced disconnect/shutdown drains sockets, refreshes DNS, and exits cleanly.

32
context/Repo-layout.md Normal file
View File

@@ -0,0 +1,32 @@
## Repo layout
- Entry points & metadata
- `SABnzbd.py`: starts the app.
- `README.md` / `README.mkd`: release notes and overview.
- `requirements.txt`: runtime deps.
- Core application package `sabnzbd/`
- Download engine: `downloader.py` (main loop), `newswrapper.py` (NNTP connections), `urlgrabber.py`, `nzbqueue.py` (queue), `nzbparser.py` (parse NZB), `assembler.py` (writes decoded parts), `decoder.py` (yEnc/UU decode), `articlecache.py` (in-memory/on-disk cache).
- Post-processing: `newsunpack.py`, `postproc.py`, `directunpacker.py`, `sorting.py`, `deobfuscate_filenames.py`.
- Config/constants/utilities: `cfg.py`, `config.py`, `constants.py`, `misc.py`, `filesystem.py`, `encoding.py`, `lang.py`, `scheduler.py`, `notifier.py`, `emailer.py`, `rss.py`.
- UI plumbing: `interface.py`, `skintext.py`, `version.py`, platform helpers (`macosmenu.py`, `sabtray*.py`).
- Subpackages: `sabnzbd/nzb/` (NZB model objects), `sabnzbd/utils/` (helpers).
- Web interfaces & assets
- `interfaces/Glitter`, `interfaces/Config`, `interfaces/wizard`: HTML/JS/CSS skins.
- `icons/`: tray/web icons.
- `locale/`, `po/`, `tools/`: translation sources and helper scripts (`make_mo.py`, etc.).
- Testing & samples
- `tests/`: pytest suite plus `data/` fixtures and `test_utils/`.
- `scripts/`: sample post-processing hooks (`Sample-PostProc.*`).
- Packaging/build
- `builder/`: platform build scripts (DMG/EXE specs, `package.py`, `release.py`).
- Platform folders `win/`, `macos/`, `linux/`, `snap/`: installer or platform-specific assets.
- `admin/`, `builder/constants.py`, `licenses/`: release and licensing support files.
- Documentation
- Documentation website source is stored in the `sabnzbd.github.io` repo.
- This repo is most likely located 1 level up from the root folder of this repo.
- Documentation is split per SABnzbd version, in the `wiki` folder.

View File

@@ -96,7 +96,7 @@
<div class="colmask">
<div class="padding">
<h5 class="copyright">Copyright &copy; 2007-2025 by The SABnzbd-Team (<a href="https://sabnzbd.org/" target="_blank">sabnzbd.org</a>)</h5>
<h5 class="copyright">Copyright &copy; 2007-2026 by The SABnzbd-Team (<a href="https://sabnzbd.org/" target="_blank">sabnzbd.org</a>)</h5>
<p class="copyright"><small>$T('yourRights')</small></p>
</div>

View File

@@ -188,6 +188,7 @@
</tr>
</table>
<p>$T('explain-apprise_enable')</p>
<p><a href="https://appriseit.com/" target="_blank">Apprise documentation</a></p>
<p>$T('version'): ${apprise.__version__}</p>
$show_cat_box('apprise')

View File

@@ -117,6 +117,12 @@
<input type="checkbox" name="optional" id="optional" value="1" />
<span class="desc">$T('explain-optional')</span>
</div>
<div class="field-pair advanced-settings">
<label class="config" for="pipelining_requests">$T('srv-pipelining_requests')</label>
<input type="number" name="pipelining_requests" id="pipelining_requests" min="1" max="20" value="1" />
<span class="desc">$T('explain-pipelining_requests')<br>$T('readwiki')
<a href="https://sabnzbd.org/wiki/advanced/nntp-pipelining" target="_blank">https://sabnzbd.org/wiki/advanced/nntp-pipelining</a></span>
</div>
<div class="field-pair advanced-settings">
<label class="config" for="expire_date">$T('srv-expire_date')</label>
<input type="date" name="expire_date" id="expire_date" />
@@ -248,6 +254,12 @@
<input type="checkbox" name="optional" id="optional$cur" value="1" <!--#if int($server['optional']) != 0 then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-optional')</span>
</div>
<div class="field-pair advanced-settings">
<label class="config" for="pipelining_requests$cur">$T('srv-pipelining_requests')</label>
<input type="number" name="pipelining_requests" id="pipelining_requests$cur" value="$server['pipelining_requests']" min="1" max="20" required />
<span class="desc">$T('explain-pipelining_requests')<br>$T('readwiki')
<a href="https://sabnzbd.org/wiki/advanced/nntp-pipelining" target="_blank">https://sabnzbd.org/wiki/advanced/nntp-pipelining</a></span>
</div>
<div class="field-pair advanced-settings">
<label class="config" for="expire_date$cur">$T('srv-expire_date')</label>
<input type="date" name="expire_date" id="expire_date$cur" value="$server['expire_date']" />

View File

@@ -6,8 +6,12 @@
<span class="glyphicon glyphicon-open"></span> $T('Glitter-notification-uploading') <span class="main-notification-box-file-count"></span>
</div>
<div class="main-notification-box-uploading-failed">
<span class="glyphicon glyphicon-exclamation-sign"></span> $T('Glitter-notification-upload-failed').replace('%s', '') <span class="main-notification-box-file-count"></span>
</div>
<div class="main-notification-box-queue-repair">
<span class="glyphicon glyphicon glyphicon-wrench"></span> $T('Glitter-repairQueue')
<span class="glyphicon glyphicon-wrench"></span> $T('Glitter-repairQueue')
</div>
<div class="main-notification-box-disconnect">
@@ -780,7 +784,7 @@
</tbody>
</table>
<hr/>
<p><small>Copyright &copy; 2007-2025 by The SABnzbd-Team (<a href="https://sabnzbd.org/" target="_blank">sabnzbd.org</a>)<br/>$T('yourRights') </small></p>
<p><small>Copyright &copy; 2007-2026 by The SABnzbd-Team (<a href="https://sabnzbd.org/" target="_blank">sabnzbd.org</a>)<br/>$T('yourRights') </small></p>
</div>
</div>
</div>

View File

@@ -726,6 +726,9 @@ function ViewModel() {
$('#nzbname').val('')
$('.btn-file em').html(glitterTranslate.chooseFile + '&hellip;')
}
}).fail(function(xhr, status, error) {
// Update the uploading notification text to show error
showNotification('.main-notification-box-uploading-failed', 0, error)
});
}

View File

@@ -69,6 +69,10 @@ legend,
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
.main-notification-box-uploading-failed {
color: #F95151;
}
.container,
.modal-body,
.modal-footer {

View File

@@ -1,10 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2022-2025 by The SABnzbd-Team (sabnzbd.org) -->
<!-- Copyright 2022-2026 by The SABnzbd-Team (sabnzbd.org) -->
<component type="desktop-application">
<id>org.sabnzbd.sabnzbd</id>
<metadata_license>MIT</metadata_license>
<name>SABnzbd</name>
<summary>Free and easy binary newsreader</summary>
<branding>
<color type="primary" scheme_preference="light">#e7e7e7</color>
<color type="primary" scheme_preference="dark">#444444</color>
</branding>
<description>
<p>
SABnzbd is a free and Open Source web-based binary newsreader,
@@ -17,6 +21,13 @@
and services that help automate the download process.
</p>
</description>
<keywords>
<keyword>usenet</keyword>
<keyword>nzb</keyword>
<keyword>download</keyword>
<keyword>newsreader</keyword>
<keyword>binary</keyword>
</keywords>
<categories>
<category>Network</category>
<category>FileTransfer</category>
@@ -24,34 +35,49 @@
<url type="homepage">https://sabnzbd.org</url>
<url type="bugtracker">https://github.com/sabnzbd/sabnzbd/issues</url>
<url type="vcs-browser">https://github.com/sabnzbd/sabnzbd</url>
<url type="contribute">https://github.com/sabnzbd/sabnzbd</url>
<url type="translate">https://sabnzbd.org/wiki/translate</url>
<url type="donation">https://sabnzbd.org/donate</url>
<url type="help">https://sabnzbd.org/wiki/</url>
<url type="faq">https://sabnzbd.org/wiki/faq</url>
<url type="contact">https://sabnzbd.org/live-chat.html</url>
<releases>
<release version="4.6.0" date="2025-12-24" type="stable"/>
<release version="4.5.5" date="2025-10-24" type="stable"/>
<release version="4.5.4" date="2025-10-22" type="stable"/>
<release version="4.5.3" date="2025-08-25" type="stable"/>
<release version="4.5.2" date="2025-07-09" type="stable"/>
<release version="4.5.1" date="2025-04-11" type="stable"/>
<release version="4.5.0" date="2025-04-01" type="stable"/>
<release version="4.4.1" date="2024-12-23" type="stable"/>
<release version="4.4.0" date="2024-12-09" type="stable"/>
<release version="4.3.3" date="2024-08-01" type="stable"/>
<release version="4.3.2" date="2024-05-30" type="stable"/>
<release version="4.3.1" date="2024-05-03" type="stable"/>
<release version="4.3.0" date="2024-05-01" type="stable"/>
<release version="4.2.2" date="2024-02-01" type="stable"/>
<release version="4.2.1" date="2024-01-05" type="stable"/>
<release version="4.2.0" date="2024-01-03" type="stable"/>
<release version="4.1.0" date="2023-09-26" type="stable"/>
<release version="4.0.3" date="2023-06-16" type="stable"/>
<release version="4.0.2" date="2023-06-09" type="stable"/>
<release version="4.0.1" date="2023-05-01" type="stable"/>
<release version="4.0.0" date="2023-04-28" type="stable"/>
<release version="3.7.2" date="2023-02-05" type="stable"/>
<release version="5.0.0" date="2026-03-01" type="stable">
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/5.0.0</url>
</release>
<release version="4.5.5" date="2025-10-24" type="stable">
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/4.5.5</url>
</release>
<release version="4.5.4" date="2025-10-22" type="stable">
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/4.5.4</url>
</release>
<release version="4.5.3" date="2025-08-25" type="stable">
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/4.5.3</url>
</release>
<release version="4.5.2" date="2025-07-09" type="stable">
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/4.5.2</url>
</release>
<release version="4.5.1" date="2025-04-11" type="stable">
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/4.5.1</url>
</release>
<release version="4.5.0" date="2025-04-01" type="stable">
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/4.5.0</url>
</release>
<release version="4.4.1" date="2024-12-23" type="stable">
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/4.4.1</url>
</release>
<release version="4.4.0" date="2024-12-09" type="stable">
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/4.4.0</url>
</release>
<release version="4.3.3" date="2024-08-01" type="stable">
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/4.3.3</url>
</release>
<release version="4.3.2" date="2024-05-30" type="stable">
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/4.3.2</url>
</release>
<release version="4.3.1" date="2024-05-03" type="stable">
<url type="details">https://github.com/sabnzbd/sabnzbd/releases/tag/4.3.1</url>
</release>
</releases>
<launchable type="desktop-id">sabnzbd.desktop</launchable>
<provides>
@@ -74,11 +100,59 @@
<screenshots>
<screenshot type="default">
<image>https://sabnzbd.org/images/landing/screenshots/interface.png</image>
<caption>Web interface</caption>
<caption>Intuitive interface</caption>
</screenshot>
<screenshot>
<image>https://sabnzbd.org/images/landing/screenshots/night-mode.png</image>
<caption>Night mode</caption>
<caption>Also comes in Night-mode</caption>
</screenshot>
<screenshot>
<image>https://sabnzbd.org/images/landing/screenshots/add-nzb.png</image>
<caption>Add NZB's or use drag-and-drop!</caption>
</screenshot>
<screenshot>
<image>https://sabnzbd.org/images/landing/screenshots/phone-interface.png</image>
<caption>Scales to any screen size</caption>
</screenshot>
<screenshot>
<image>https://sabnzbd.org/images/landing/screenshots/history-details.png</image>
<caption>Easy overview of all history details</caption>
</screenshot>
<screenshot>
<image>https://sabnzbd.org/images/landing/screenshots/phone-extra.png</image>
<caption>Every option, on every screen size</caption>
</screenshot>
<screenshot>
<image>https://sabnzbd.org/images/landing/screenshots/file-lists.png</image>
<caption>Manage a job's individual files</caption>
</screenshot>
<screenshot>
<image>https://sabnzbd.org/images/landing/screenshots/set-speedlimit.png</image>
<caption>Easy speed limiting</caption>
</screenshot>
<screenshot>
<image>https://sabnzbd.org/images/landing/screenshots/set-options.png</image>
<caption>Quickly change settings</caption>
</screenshot>
<screenshot>
<image>https://sabnzbd.org/images/landing/screenshots/dashboard.png</image>
<caption>Easy system check</caption>
</screenshot>
<screenshot>
<image>https://sabnzbd.org/images/landing/screenshots/connections-overview.png</image>
<caption>See active connections</caption>
</screenshot>
<screenshot>
<image>https://sabnzbd.org/images/landing/screenshots/skin-settings.png</image>
<caption>Customize the interface</caption>
</screenshot>
<screenshot>
<image>https://sabnzbd.org/images/landing/screenshots/tabbed.png</image>
<caption>Tabbed-mode</caption>
</screenshot>
<screenshot>
<image>https://sabnzbd.org/images/landing/screenshots/set-custom-pause.png</image>
<caption>Specify any pause duration</caption>
</screenshot>
<screenshot>
<image>https://sabnzbd.org/images/landing/screenshots/config.png</image>

View File

Binary file not shown.

View File

Binary file not shown.

View File

@@ -1,10 +1,10 @@
#
# SABnzbd Translation Template file EMAIL
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by The SABnzbd-Team (sabnzbd.org)
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\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.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\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

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

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Fred L <88com88@gmail.com>, 2025\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.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\n"
"Language-Team: Hebrew (https://app.transifex.com/sabnzbd/teams/111101/he/)\n"

View File

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

View File

@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Language-Team: Norwegian Bokmål (https://app.transifex.com/sabnzbd/teams/111101/nb/)\n"
"MIME-Version: 1.0\n"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: mauron, 2025\n"
"Language-Team: Turkish (https://app.transifex.com/sabnzbd/teams/111101/tr/)\n"

View File

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

View File

@@ -1,10 +1,10 @@
#
# SABnzbd Translation Template file MAIN
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by The SABnzbd-Team (sabnzbd.org)
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: team@sabnzbd.org\n"
"Language-Team: SABnzbd <team@sabnzbd.org>\n"
@@ -125,6 +125,11 @@ msgstr ""
msgid "Current umask (%o) might deny SABnzbd access to the files and folders it creates."
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid "Completed Download Folder %s is on FAT file system, limiting maximum file size to 4GB"
@@ -279,7 +284,7 @@ msgstr ""
msgid "Unwanted extension is in rar file %s"
msgstr ""
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr ""
@@ -670,6 +675,11 @@ msgstr ""
msgid "%s is not writable with special character filenames. This can cause problems."
msgstr ""
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr ""
@@ -884,7 +894,7 @@ msgid "Update Available!"
msgstr ""
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr ""
@@ -1300,103 +1310,18 @@ msgstr ""
msgid "NZB added to queue"
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr ""
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr ""
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "%s articles had non-matching duplicates"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr ""
@@ -1638,6 +1563,14 @@ msgstr ""
msgid "Received a DBus exception %s"
msgstr ""
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr ""
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr ""
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1664,14 +1597,6 @@ msgstr ""
msgid "RSS Feed %s was empty"
msgstr ""
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr ""
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr ""
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr ""
@@ -3482,6 +3407,14 @@ msgstr ""
msgid "Enable"
msgstr ""
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid "Request multiple articles per connection without waiting for each response first.<br />This can improve download speeds, especially on connections with higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4189,6 +4122,11 @@ msgstr ""
msgid "Filename"
msgstr ""
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr ""
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr ""
@@ -4598,6 +4536,10 @@ msgstr ""
msgid "Server could not complete request"
msgstr ""
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr ""
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\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"
@@ -144,6 +144,11 @@ msgid ""
"creates."
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -316,7 +321,7 @@ msgstr ""
msgid "Unwanted extension is in rar file %s"
msgstr "Neočekávaná přípona v rar souboru %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "Přerušeno, nalezena neočekávaná připona"
@@ -726,6 +731,11 @@ msgid ""
"problems."
msgstr ""
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Odmítnuto spojení z:"
@@ -955,7 +965,7 @@ msgid "Update Available!"
msgstr "Dostupná aktualizace!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr "Nezdařilo se nahrát soubor: %s"
@@ -1388,103 +1398,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
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignoruji duplikátní NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Nezdařilo se duplikovat NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr "Duplikátní NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Prázdný NZB soubor %s"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr "Nechtěná přípona v souboru %s (%s)"
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "Zrušeno, nelze dokončit"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Chyba při importu %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "DUPLIKÁT"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "ŠIFROVANÉ"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "PŘÍLIŠ VELKÝ"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "NEKOMPLETNÍ"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "NECHTĚNÝ"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "ČEKÁNÍ %s s"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr "PROPAGUJI %s min"
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "Staženo do %s s průměrnou rychlostí %s B/s"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Stáří"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "%s articles had non-matching duplicates"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Pozastavuji duplikátní NZB \"%s\""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Problém s"
@@ -1729,6 +1654,14 @@ msgstr ""
msgid "Received a DBus exception %s"
msgstr ""
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Prázdný RSS záznam nalezen (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Nekompatibilní kanál"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1755,14 +1688,6 @@ msgstr ""
msgid "RSS Feed %s was empty"
msgstr "RSS kanál %s byl prázdný"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Nekompatibilní kanál"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Prázdný RSS záznam nalezen (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Zobrazit rozhraní"
@@ -3672,6 +3597,17 @@ msgstr ""
msgid "Enable"
msgstr ""
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4413,6 +4349,11 @@ msgstr ""
msgid "Filename"
msgstr ""
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Stáří"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr ""
@@ -4832,6 +4773,10 @@ msgstr ""
msgid "Server could not complete request"
msgstr ""
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Prázdný NZB soubor %s"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\n"
"Language-Team: Danish (https://app.transifex.com/sabnzbd/teams/111101/da/)\n"
@@ -147,6 +147,11 @@ msgid ""
msgstr ""
"Aktuel umask (%o) kan nægte SABnzbd adgang til filer og mapper den opretter."
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -331,7 +336,7 @@ msgstr "I \"%s\" uønsket extension i RAR fil. Uønsket fil er \"%s\" "
msgid "Unwanted extension is in rar file %s"
msgstr "Uønsket extension i rar fil %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "Afbrudt, uønsket extension fundet"
@@ -764,6 +769,11 @@ msgid ""
msgstr ""
"%s er ikke skrivbar med filnavne med specialtegn. Dette kan give problemer."
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Afviste forbindelse fra:"
@@ -996,7 +1006,7 @@ msgid "Update Available!"
msgstr "Opdatering tilgængelig!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr "Kunne ikke uploade fil: %s"
@@ -1432,103 +1442,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
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorerer identiske NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Fejler dublet NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr "Dublet NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr "Ødelagt NZB fil %s, springer over (årsag=%s)"
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Tom NZB fil %s"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr "Før-kø script job markeret som mislykkedet"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr "Uønsket filtype i fil %s (%s)"
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "Afbrudt, kan ikke afsluttes"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Det lykkedes ikke at importere %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "DUPLIKERE"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr "ALTERNATIV"
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "KRYPTEREDE"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "FOR STOR"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "UFULDSTÆNDIG"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "UØNSKET"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "VENT %s sekunder"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr "PROPAGATING %s min"
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "Hentede i %s med et gennemsnit på %sB/s"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Alder"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s artikler misdannede"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s artikler manglede"
#: sabnzbd/nzbstuff.py
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\""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Problem med"
@@ -1803,6 +1728,14 @@ msgstr "Fejl ved lukning af system"
msgid "Received a DBus exception %s"
msgstr "Modtog en DBus-undtagelse %s"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Tom RSS post blev fundet (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Inkompatibel feed"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1829,14 +1762,6 @@ msgstr "Server %s bruger et upålideligt HTTPS-certifikat"
msgid "RSS Feed %s was empty"
msgstr "RSS Feed %s er tom"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Inkompatibel feed"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Tom RSS post blev fundet (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Vis grænseflade"
@@ -3845,6 +3770,17 @@ msgstr ""
msgid "Enable"
msgstr "Aktivere"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4620,6 +4556,11 @@ msgstr "Slet"
msgid "Filename"
msgstr "Filnavn"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Alder"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "Ledig diskplads"
@@ -5053,6 +4994,10 @@ msgstr "Fil ikke på server"
msgid "Server could not complete request"
msgstr "Serveren kunne ikke fuldføre anmodningen"
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Tom NZB fil %s"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -20,7 +20,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\n"
"Language-Team: German (https://app.transifex.com/sabnzbd/teams/111101/de/)\n"
@@ -167,6 +167,11 @@ msgstr ""
"Die aktuellen Zugriffseinstellungen (%o) könnte SABnzbd den Zugriff auf die "
"erstellten Dateien und Ordner von SABnzbd verweigern."
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -357,7 +362,7 @@ msgstr "Unerwünschter Typ \"%s\" in RAR Datei. Unerwünschte Datei ist %s "
msgid "Unwanted extension is in rar file %s"
msgstr "Unerwünschter Dateityp im RAR-Archiv %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "Abgebrochen, unerwünschte Dateieindung gefunden"
@@ -803,6 +808,11 @@ msgstr ""
"Dateinamen mit Umlaute können nicht in %s gespeichert werden. Dies kann zu "
"Problemen führen."
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Abgelehnte Verbindung von:"
@@ -1036,7 +1046,7 @@ msgid "Update Available!"
msgstr "Neue Version verfügbar!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr "Hochladen fehlgeschlagen: %s"
@@ -1479,106 +1489,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
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Doppelte NZB \"%s\" wird ignoriert"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr "kopieren der NZB \"%s\" fehlgeschlagen"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr "Doppelte NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr "Ungültige NZB-Datei %s wird übersprungen (Fehler: %s)"
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Leere NZB-Datei %s"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr ""
"Das Vorwarteschlangen (pre-queue) Skript hat die Downloadaufgabe als "
"gescheitert markiert"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr "Ungewollte Dateiendung in der Datei %s (%s)"
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "Abgebrochen, kann nicht fertiggestellt werden"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Fehler beim Importieren von %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "DUPLIKAT"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr "ALTERNATIVE"
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "VERSCHLÜSSELT"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "ZU GROSS"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "UNVOLLSTÄNDIG"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "UNERWÜNSCHT"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "WARTE %s Sek"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr "AUSBREITUNG %s min"
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr ""
"Heruntergeladen in %s mit einer Durchschnittsgeschwindigkeit von %sB/s"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Alter"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s Artikel hatten ein ungültiges Format"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s Artikel fehlten"
#: sabnzbd/nzbstuff.py
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"
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Problem mit"
@@ -1862,6 +1784,14 @@ msgstr "Fehler beim Herunterfahren des Systems"
msgid "Received a DBus exception %s"
msgstr "DBus-Ausnahmefehler empfangen %s "
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Leerer RSS-Feed gefunden: %s"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Inkompatibeler RSS-Feed"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1888,14 +1818,6 @@ msgstr "Der Server %s nutzt ein nicht vertrauenswürdiges HTTPS-Zertifikat"
msgid "RSS Feed %s was empty"
msgstr "RSS-Feed %s war leer"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Inkompatibeler RSS-Feed"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Leerer RSS-Feed gefunden: %s"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Interface anzeigen"
@@ -3954,6 +3876,17 @@ msgstr "Für unzuverlässige Server, wird bei Fehlern länger ignoriert"
msgid "Enable"
msgstr "Aktivieren"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4737,6 +4670,11 @@ msgstr "Löschen"
msgid "Filename"
msgstr "Dateiname"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Alter"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "Freier Speicherplatz"
@@ -5171,6 +5109,10 @@ msgstr "Datei nicht auf dem Server"
msgid "Server could not complete request"
msgstr "Server konnte nicht vollständig antworten"
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Leere NZB-Datei %s"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -9,7 +9,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\n"
"Language-Team: Spanish (https://app.transifex.com/sabnzbd/teams/111101/es/)\n"
@@ -156,6 +156,11 @@ msgstr ""
"La umask actual (%o) podría denegarle acceso a SABnzbd a los archivos y "
"carpetas que este crea."
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -342,7 +347,7 @@ msgstr ""
msgid "Unwanted extension is in rar file %s"
msgstr "Se ha encontrado una extensión desconocida en el fichero rar %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "Se interrumpió la acción porque se detectó una extensión no deseada"
@@ -787,6 +792,11 @@ msgstr ""
"%s no permite escribir nombres de archivo con caracteres especiales. Esto "
"puede causar problemas."
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Conexión rechazada de:"
@@ -1020,7 +1030,7 @@ msgid "Update Available!"
msgstr "¡Actualización Disponible!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr "Error al subir archivo: %s"
@@ -1471,105 +1481,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
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorando NZB Duplicado \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Fallo al duplicar NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr "Duplicar NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr "Fichero NBZ inválido: %s, omitiendo (razón=%s)"
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Fichero NZB vacío: %s"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr ""
"La secuencia de comandos de la cola preestablecida ha marcado la tarea como "
"fallida"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr "Extensión no deseada en el archivo %s (%s)"
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "Abortado, No puede ser completado"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Error importando %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "DUPLICADO"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr "ALTERNATIVO"
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "ENCRIPTADO"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "DEMASIADO GRANDE"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "INCOMPLETO"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "NO DESEADO"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "ESPERAR %s seg"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr "PROPAGANDO %s min"
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "Descargado en %s a una media de %sB/s"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Edad"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s artículos estaban mal formados."
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s artículos no encontrados"
#: sabnzbd/nzbstuff.py
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\""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Problema con"
@@ -1849,6 +1772,14 @@ msgstr "Error al apagarel sistema"
msgid "Received a DBus exception %s"
msgstr "Se ha recibido una excepción DBus %s"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Entrada RSS vacía (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Canal Incorrecto"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1877,14 +1808,6 @@ msgstr "El servidor %s utiliza un certificado HTTPS no fiable"
msgid "RSS Feed %s was empty"
msgstr "El canal RSS %s estaba vacío"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Canal Incorrecto"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Entrada RSS vacía (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Mostrar interfaz"
@@ -3924,6 +3847,17 @@ msgstr ""
msgid "Enable"
msgstr "Habilitar"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4706,6 +4640,11 @@ msgstr "Eliminar"
msgid "Filename"
msgstr "Nombre de archivo"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Edad"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "Espacio libre"
@@ -5142,6 +5081,10 @@ msgstr "El fichero no se encuentra en el servidor"
msgid "Server could not complete request"
msgstr "El servidor no ha podido completar la solicitud"
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Fichero NZB vacío: %s"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\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"
@@ -146,6 +146,11 @@ msgid ""
"creates."
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -315,7 +320,7 @@ msgstr ""
msgid "Unwanted extension is in rar file %s"
msgstr "Ei toivottu tiedostopääte on rar arkistossa %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "Peruutettu, ei toivottu tiedostopääte havaittu"
@@ -732,6 +737,11 @@ msgid ""
"problems."
msgstr ""
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr ""
@@ -961,7 +971,7 @@ msgid "Update Available!"
msgstr "Päivitys saatavilla!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr ""
@@ -1387,103 +1397,18 @@ msgstr "Virhe ladattaessa %s, korruptoitunut tiedosto havaittu"
msgid "NZB added to queue"
msgstr "NZB lisätty jonoon"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ohitetaan kaksoiskappale NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Tyhjä NZB tiedosto %s"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "Peruutettu, ei voi valmistua"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Virhe tuotaessa %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "KAKSOISKAPPALE"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "SALATTU"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "LIIAN SUURI"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "KESKENERÄINEN"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "EI TOIVOTTU"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "ODOTA %s sekuntia"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr "LEVITETÄÄN %s min"
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "Ladattiin ajassa %s keskilatausnopeudella %sB/s"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Ikä"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s artikkelia oli väärin muotoiltuja"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s artikkelia puuttui"
#: sabnzbd/nzbstuff.py
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\""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Ongelma"
@@ -1756,6 +1681,14 @@ msgstr "Virhe sammutettaessa järjestelmää"
msgid "Received a DBus exception %s"
msgstr ""
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Tyhjä RSS kohde löytyi (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Puutteellinen syöte"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1782,14 +1715,6 @@ msgstr "Palvelin %s käyttää epäluotettavaa HTTPS sertifikaattia"
msgid "RSS Feed %s was empty"
msgstr "RSS syöte %s oli tyhjä"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Puutteellinen syöte"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Tyhjä RSS kohde löytyi (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Näytä käyttöliittymä"
@@ -3763,6 +3688,17 @@ msgstr ""
msgid "Enable"
msgstr "Ota käyttöön"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4519,6 +4455,11 @@ msgstr "Poista"
msgid "Filename"
msgstr "Tiedostonimi"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Ikä"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "Vapaa tila"
@@ -4949,6 +4890,10 @@ msgstr "Tiedostoa ei ole palvelimella"
msgid "Server could not complete request"
msgstr ""
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Tyhjä NZB tiedosto %s"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -3,13 +3,13 @@
#
# Translators:
# Safihre <safihre@sabnzbd.org>, 2025
# Fred L <88com88@gmail.com>, 2025
# Fred L <88com88@gmail.com>, 2026
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Fred L <88com88@gmail.com>, 2025\n"
"Last-Translator: Fred L <88com88@gmail.com>, 2026\n"
"Language-Team: French (https://app.transifex.com/sabnzbd/teams/111101/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -157,6 +157,13 @@ msgstr ""
"L'umask actuel (%o) pourrait refuser à SABnzbd l'accès aux fichiers et "
"dossiers qu'il crée."
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
"La version Windows ARM de SABnzbd est disponible depuis notre page "
"Téléchargements!"
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -347,7 +354,7 @@ msgstr ""
msgid "Unwanted extension is in rar file %s"
msgstr "L'extension indésirable est dans le fichier rar %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "Interrompu, extension indésirable détectée"
@@ -792,6 +799,13 @@ msgstr ""
"Le fichier %s n'est pas inscriptible à cause des caractères spéciaux dans le"
" nom. Cela peut causer des problèmes."
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
"%s ne prend pas en charge les fichiers fragmentés. Désactivation du mode "
"d'écriture directe."
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Connexion refusée de:"
@@ -1025,7 +1039,7 @@ msgid "Update Available!"
msgstr "Mise à Jour disponible!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr "Échec de l'upload du fichier : %s"
@@ -1466,103 +1480,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
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Doublon NZB ignoré \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Échec de duplication du NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr "Dupliquer NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr "Fichier NZB %s invalide, sera ignoré (erreur : %s)"
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Fichier NZB %s vide"
#: sabnzbd/nzbstuff.py
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 "Unwanted Extension in file %s (%s)"
msgstr "Extension non souhaitée dans le fichier %s (%s)"
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "Interrompu, ne peut être achevé"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Erreur lors de l'importation de %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "DOUBLON"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr "ALTERNATIVE"
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "CHIFFRÉ"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "TROP VOLUMINEUX"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "INCOMPLET"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "INDÉSIRABLE"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "PATIENTER %s sec"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr "PROPAGATION %s min"
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "Téléchargé en %s à %sB/s de moyenne"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Âge"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s articles malformés"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s articles manquants"
#: sabnzbd/nzbstuff.py
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\""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Problème avec"
@@ -1845,6 +1774,14 @@ msgstr "Erreur lors de l'arrêt du système"
msgid "Received a DBus exception %s"
msgstr "Exception DBus reçue %s"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Entrée vide de flux RSS trouvée (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Flux incompatible"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1872,14 +1809,6 @@ msgstr "Le serveur %s utilise un certificat de sécurité HTTPS non authentifié
msgid "RSS Feed %s was empty"
msgstr "Le flux RSS %s était vide"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Flux incompatible"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Entrée vide de flux RSS trouvée (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Afficher linterface"
@@ -3505,6 +3434,8 @@ msgstr "Activer les contrôles SFV"
msgid ""
"If no par2 files are available, use sfv files (if present) to verify files"
msgstr ""
"Si aucun fichier par2 n'est disponible, utiliser les fichiers sfv (si "
"présents) pour vérifier les fichiers"
#: sabnzbd/skintext.py
msgid "User script can flag job as failed"
@@ -3935,6 +3866,20 @@ msgstr ""
msgid "Enable"
msgstr "Activer"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr "Articles par demande"
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
" Demandez plusieurs articles par connexion sans attendre chaque réponse.<br "
"/>Cela peut améliorer les vitesses de téléchargement, en particulier sur les"
" connexions à latence élevée. "
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4720,6 +4665,11 @@ msgstr "Supprimer"
msgid "Filename"
msgstr "Nom de fichier"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Âge"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "Espace libre"
@@ -5158,6 +5108,10 @@ msgstr "Fichier introuvable sur le serveur"
msgid "Server could not complete request"
msgstr "Le serveur n'a pas pu terminer la requête"
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Fichier NZB %s vide"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\n"
"Language-Team: Hebrew (https://app.transifex.com/sabnzbd/teams/111101/he/)\n"
@@ -143,6 +143,11 @@ msgstr ""
"פקודת umask נוכחית (%o) עשויה לדחות גישה מן SABnzbd אל הקבצים והתיקיות שהוא "
"יוצר."
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -320,7 +325,7 @@ msgstr "בעבודה \"%s\" יש סיומת בלתי רצויה בתוך קוב
msgid "Unwanted extension is in rar file %s"
msgstr "סיומת בלתי רצויה בקובץ rar %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "בוטל, סיומת בלתי רצויה התגלתה"
@@ -745,6 +750,11 @@ msgid ""
"problems."
msgstr "%s אינו בר־כתיבה עם שמות קבצים עם תו מיוחד. זה יכול לגרום לבעיות."
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "חיבור מסורב מאת:"
@@ -973,7 +983,7 @@ msgid "Update Available!"
msgstr "עדכון זמין!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr "כישלון בהעלאת קובץ: %s"
@@ -1404,103 +1414,18 @@ msgstr "שגיאה בטעינת %s, קובץ פגום התגלה"
msgid "NZB added to queue"
msgstr "NZB התווסף לתור"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "מתעלם מן NZB כפול \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr "מכשיל NZB כפול \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr "NZB כפול"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr "קובץ NZB בלתי תקף %s, מדלג (שגיאה: %s)"
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "קובץ NZB ריק %s"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr "תסריט קדם־תור סומן כנכשל"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr "סיומת בלתי רצויה בקובץ %s (%s)"
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "בוטל, לא יכול להיות שלם"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "שגיאה ביבוא %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "כפול"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr "חלופה"
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "מוצפן"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "גדול מדי"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "בלתי שלם"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "בלתי רצוי"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "המתן %s שניות"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr "מפיץ %s דקות"
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "ירד תוך %s בממוצע של %s ב/ש"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "גיל"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s מאמרים עוותו"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s מאמרים היו חסרים"
#: sabnzbd/nzbstuff.py
msgid "%s articles had non-matching duplicates"
msgstr "אל %s מאמרים יש כפילויות בלתי תואמות"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "משהה NZB כפול \"%s\""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "בעיה עם"
@@ -1775,6 +1700,14 @@ msgstr "שגיאה בזמן כיבוי מערכת"
msgid "Received a DBus exception %s"
msgstr "חריגת DBus התקבלה %s"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "כניסת RSS ריקה נמצאה (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "הזנה בלתי תואמת"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1801,14 +1734,6 @@ msgstr "השרת %s משתמש בתעודת HTTPS בלתי מהימנה"
msgid "RSS Feed %s was empty"
msgstr "הזנת RSS %s הייתה ריקה"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "הזנה בלתי תואמת"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "כניסת RSS ריקה נמצאה (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "הראה ממשק"
@@ -3781,6 +3706,17 @@ msgstr "עבור שרתים בלתי מהימנים, ייתקל בהתעלמות
msgid "Enable"
msgstr "אפשר"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4546,6 +4482,11 @@ msgstr "מחק"
msgid "Filename"
msgstr "שם קובץ"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "גיל"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "שטח פנוי"
@@ -4979,6 +4920,10 @@ msgstr "קובץ לא על השרת"
msgid "Server could not complete request"
msgstr "השרת לא היה יכול להשלים בקשה"
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "קובץ NZB ריק %s"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\n"
"Language-Team: Italian (https://app.transifex.com/sabnzbd/teams/111101/it/)\n"
@@ -150,6 +150,11 @@ msgstr ""
"L'umask corrente (%o) potrebbe negare a SABnzbd l'accesso ai file e alle "
"cartelle che crea."
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -340,7 +345,7 @@ msgstr ""
msgid "Unwanted extension is in rar file %s"
msgstr "L'estensione non desiderata è nel file rar %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "Annullato, rilevata estensione non desiderata"
@@ -783,6 +788,11 @@ msgstr ""
"%s non è scrivibile con nomi di file con caratteri speciali. Questo può "
"causare problemi."
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Connessione rifiutata da:"
@@ -1016,7 +1026,7 @@ msgid "Update Available!"
msgstr "Aggiornamento disponibile!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr "Caricamento del file %s fallito"
@@ -1454,103 +1464,18 @@ msgstr "Errore durante il caricamento di %s, rilevato file corrotto"
msgid "NZB added to queue"
msgstr "NZB aggiunto alla coda"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorando NZB duplicato \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Fallimento NZB duplicato \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr "NZB duplicato"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr "File NZB non valido %s, saltato (errore: %s)"
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "File NZB vuoto %s"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr "Lo script pre-coda ha contrassegnato il processo come fallito"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr "Estensione non desiderata nel file %s (%s)"
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "Annullato, non può essere completato"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Errore durante l'importazione di %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "DUPLICATO"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr "ALTERNATIVO"
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "CRITTOGRAFATO"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "TROPPO GRANDE"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "INCOMPLETO"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "NON DESIDERATO"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "ATTENDI %s sec"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr "PROPAGAZIONE %s min"
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "Scaricato in %s a una media di %sB/s"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Età"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s articoli erano malformati"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s articoli erano mancanti"
#: sabnzbd/nzbstuff.py
msgid "%s articles had non-matching duplicates"
msgstr "%s articoli avevano duplicati non corrispondenti"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Messa in pausa NZB duplicato \"%s\""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Problema con"
@@ -1826,6 +1751,14 @@ msgstr "Errore durante lo spegnimento del sistema"
msgid "Received a DBus exception %s"
msgstr "Ricevuta un'eccezione DBus %s"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Trovata voce RSS vuota (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Feed incompatibile"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1852,14 +1785,6 @@ msgstr "Il server %s utilizza un certificato HTTPS non attendibile"
msgid "RSS Feed %s was empty"
msgstr "Il feed RSS %s era vuoto"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Feed incompatibile"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Trovata voce RSS vuota (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Mostra interfaccia"
@@ -3894,6 +3819,17 @@ msgstr ""
msgid "Enable"
msgstr "Abilita"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4675,6 +4611,11 @@ msgstr "Elimina"
msgid "Filename"
msgstr "Nome file"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Età"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "Spazio libero"
@@ -5111,6 +5052,10 @@ msgstr "File non presente sul server"
msgid "Server could not complete request"
msgstr "Il server non ha potuto completare la richiesta"
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "File NZB vuoto %s"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\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"
@@ -142,6 +142,11 @@ msgid ""
"creates."
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -313,7 +318,7 @@ msgstr ""
msgid "Unwanted extension is in rar file %s"
msgstr "Uønsket forlenging finnes i rar fil %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "Avbryt, uønsket forlenging oppdaget"
@@ -729,6 +734,11 @@ msgid ""
"problems."
msgstr ""
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr ""
@@ -958,7 +968,7 @@ msgid "Update Available!"
msgstr "Oppdatering tilgjengelig"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr ""
@@ -1385,103 +1395,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
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorerer duplikatfil \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Tom NZB-fil %s"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "Avbrutt, kan ikke fullføres"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Kunne ikke importere %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "DUPLIKAT"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "KRYPTERT"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "FOR STOR"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "UFULLSTENDIG"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "UØNSKET"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "VENT %s sek"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "Hentet filer på %s med gjenomsnitts hastighet på %sB/s"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Tid"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s artikler var korrupte"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s artikler manglet"
#: sabnzbd/nzbstuff.py
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\""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Problem med"
@@ -1754,6 +1679,14 @@ msgstr "Feil under avslutting av systemet"
msgid "Received a DBus exception %s"
msgstr ""
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Tom RSS post funnet (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Ukompatibel nyhetsstrøm"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1780,14 +1713,6 @@ msgstr "Server %s bruker et usikkert HTTP sertifikat"
msgid "RSS Feed %s was empty"
msgstr "RSS-kilde %s var tom"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Ukompatibel nyhetsstrøm"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Tom RSS post funnet (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Vis grensesnitt"
@@ -3742,6 +3667,17 @@ msgstr ""
msgid "Enable"
msgstr "Aktivere"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4493,6 +4429,11 @@ msgstr "Fjern"
msgid "Filename"
msgstr "Filnavn"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Tid"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "Ledig plass"
@@ -4921,6 +4862,10 @@ msgstr ""
msgid "Server could not complete request"
msgstr ""
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Tom NZB-fil %s"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -8,7 +8,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\n"
"Language-Team: Dutch (https://app.transifex.com/sabnzbd/teams/111101/nl/)\n"
@@ -152,6 +152,11 @@ msgstr ""
"Huidige umask (%o) zou kunnen beletten dat SABnzbd toegang heeft tot de "
"aangemaakte bestanden en mappen."
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -337,7 +342,7 @@ msgstr "Ongewenste extensie ontdekt in \"%s\". Het ongewenste bestand is \"%s\"
msgid "Unwanted extension is in rar file %s"
msgstr "De ongewenste extensie zit in RAR-bestand %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "Afgebroken, ongewenste extensie ontdekt"
@@ -786,6 +791,11 @@ msgstr ""
"Het is niet mogelijk bestanden met speciale tekens op te slaan in %s. Dit "
"geeft mogelijk problemen bij het verwerken van downloads."
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Verbinding geweigerd van: "
@@ -1019,7 +1029,7 @@ msgid "Update Available!"
msgstr "Update beschikbaar!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr "Kon het volgende bestand niet uploaden: %s"
@@ -1457,103 +1467,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
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Dubbele download \"%s\" overgeslagen"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Download '%s' geweigerd omdat het een dubbele is"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr "Dubbele download"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr "Corrupte NZB %s wordt overgeslagen (foutmelding: %s)"
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "NZB-bestand %s is leeg"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr "Wachtrij filter script heeft de download afgekeurd"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr "Ongewenste extensie gevonden in %s (%s) "
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "Afgebroken, kan niet voltooid worden"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Fout bij importeren van %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "DUBBEL"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr "ALTERNATIEF"
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "VERSLEUTELD"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "TE GROOT"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "ONVOLLEDIG"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "ONGEWENST"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "WACHT %s sec"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr "VERSPREIDINGSWACHTTIJD %s min"
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "Gedownload in %s met een gemiddelde snelheid van %sB/s"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Leeftijd"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s artikelen zijn misvormd"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s artikelen ontbreken"
#: sabnzbd/nzbstuff.py
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"
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Probleem met"
@@ -1829,6 +1754,14 @@ msgstr "Fout bij het afsluiten van het systeem"
msgid "Received a DBus exception %s"
msgstr "DBus foutmelding %s "
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Lege RSS-feed gevonden (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Ongeschikte RSS-feed"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1855,14 +1788,6 @@ msgstr "Server %s gebruikt een onbetrouwbaar HTTPS-certificaat"
msgid "RSS Feed %s was empty"
msgstr "RSS-feed %s is leeg"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Ongeschikte RSS-feed"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Lege RSS-feed gevonden (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Toon webinterface"
@@ -3894,6 +3819,17 @@ msgstr ""
msgid "Enable"
msgstr "Inschakelen"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4673,6 +4609,11 @@ msgstr "Verwijder"
msgid "Filename"
msgstr "Bestandsnaam"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Leeftijd"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "Vrije ruimte"
@@ -5107,6 +5048,10 @@ msgstr "Bestand bestaat niet op de server"
msgid "Server could not complete request"
msgstr "De server kon de opdracht niet uitvoeren"
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "NZB-bestand %s is leeg"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\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"
@@ -138,6 +138,11 @@ msgid ""
"creates."
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -312,7 +317,7 @@ msgstr ""
msgid "Unwanted extension is in rar file %s"
msgstr "Niepożądane rozszerzenie w pliku RAR %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "Przerwano, wykryto niepożądane rozszerzenie"
@@ -732,6 +737,11 @@ msgid ""
"problems."
msgstr ""
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr ""
@@ -961,7 +971,7 @@ msgid "Update Available!"
msgstr "Dostępna aktualizacja!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr ""
@@ -1390,103 +1400,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
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignoruję zduplikowany NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Pusty plik NZB %s"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "Przerwano, nie można ukończyć"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Błąd importu %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "DUPLIKAT"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "ZASZYFROWANY"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "ZA DUŻY"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "NIEKOMPLETNY"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "NIEPOŻĄDANY"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "CZEKAM %s s"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "Pobrano w %s ze średnią %sB/s"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Wiek"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s artykułów było uszkodzonych"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "Brakowało %s artykułów"
#: sabnzbd/nzbstuff.py
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\""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Problem z"
@@ -1763,6 +1688,14 @@ msgstr "Wyłączenie systemu nie powiodło się"
msgid "Received a DBus exception %s"
msgstr ""
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Znaleziono pusty wpis RSS (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Niekompatybilny kanał"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1789,14 +1722,6 @@ msgstr "Serwer %s używa niezaufanego certyfikatu HTTPS"
msgid "RSS Feed %s was empty"
msgstr "Kanał RSS %s był pusty"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Niekompatybilny kanał"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Znaleziono pusty wpis RSS (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Pokaż interfejs"
@@ -3754,6 +3679,17 @@ msgstr ""
msgid "Enable"
msgstr "Włączony"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4505,6 +4441,11 @@ msgstr "Usuń"
msgid "Filename"
msgstr "Nazwa pliku"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Wiek"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "Wolne miejsce"
@@ -4931,6 +4872,10 @@ msgstr ""
msgid "Server could not complete request"
msgstr ""
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Pusty plik NZB %s"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\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"
@@ -147,6 +147,11 @@ msgstr ""
"Mascara atual (%o) pode negar ao SABnzbd acesso aos arquivos e diretórios "
"criados."
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -324,7 +329,7 @@ msgstr ""
msgid "Unwanted extension is in rar file %s"
msgstr "A extensão indesejada está no arquivo rar %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "Cancelado, extensão indesejada detectada"
@@ -744,6 +749,11 @@ msgid ""
"problems."
msgstr ""
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr ""
@@ -973,7 +983,7 @@ msgid "Update Available!"
msgstr "Atualização Disponível!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr ""
@@ -1399,103 +1409,18 @@ msgstr "Erro ao carregar %s. Arquivo corrompido detectado"
msgid "NZB added to queue"
msgstr "NZB adicionado à fila"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorando NZB duplicado \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Arquivo NZB %s vazio"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "Cancelado, não é possível concluir"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Erro ao importar %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "DUPLICADO"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "CRIPTOGRAFADO"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "MUITO GRANDE"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "INCOMPLETO"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "INDESEJADO"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "Espere %s segundo(s)"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "Baixado em %s a uma média de %sB/s"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Idade"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s artigos estavam malformados"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s artigos estavam faltando"
#: sabnzbd/nzbstuff.py
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\""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Problema com"
@@ -1773,6 +1698,14 @@ msgstr "Erro ao desligar o sistema"
msgid "Received a DBus exception %s"
msgstr ""
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Entrada RSS vazia encontrada (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Feed incompatível"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1800,14 +1733,6 @@ msgstr "Servidor %s usa um certificado HTTPS não confiável"
msgid "RSS Feed %s was empty"
msgstr "O feed RSS %s estava vazio"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Feed incompatível"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Entrada RSS vazia encontrada (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Exibir interface"
@@ -3765,6 +3690,17 @@ msgstr ""
msgid "Enable"
msgstr "Habilitar"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4516,6 +4452,11 @@ msgstr "Eliminar"
msgid "Filename"
msgstr "Nome do arquivo"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Idade"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "Espaço Disponível"
@@ -4942,6 +4883,10 @@ msgstr ""
msgid "Server could not complete request"
msgstr ""
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Arquivo NZB %s vazio"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\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"
@@ -147,6 +147,11 @@ msgid ""
"creates."
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -326,7 +331,7 @@ msgstr "Extensie nedorită în fișierul RAR al „%s”. Fișierul nedorit este
msgid "Unwanted extension is in rar file %s"
msgstr "Extensii fișier nedorite în fișierul rar %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "Oprit, extensii nedorite detectate"
@@ -752,6 +757,11 @@ msgid ""
"problems."
msgstr ""
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr ""
@@ -983,7 +993,7 @@ msgid "Update Available!"
msgstr "Actualizare Disponibilă!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr "Eșuare la încărcarea fișierului: %s"
@@ -1417,103 +1427,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
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorăm duplicat NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr "Eșuare duplicat NZB „%s”"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr "NZB duplicat"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Fişier NZB gol %s"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr "Scriptul pre-coadă a marcat sarcina ca nereușită"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr "Extensie nedorită în fișierul %s (%s)"
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "Anulat nu poate fi finalizat"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Eroare importare %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "DUPLICAT"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "ENCRIPTAT"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "PREA MARE"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "INCOMPLET"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "NEDORIT"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "AŞTEAPTĂ %s sec"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr "SE PROPAGHEAZĂ %s min"
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "Descărcat în %s cu o medie de %sB/s"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Vârsta"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s articolele au fost incorecte"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s articolele au fost lipsă"
#: sabnzbd/nzbstuff.py
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\""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Problemă cu"
@@ -1792,6 +1717,14 @@ msgstr "Eroare la oprirea sistemului"
msgid "Received a DBus exception %s"
msgstr ""
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Valoare RSS gasită a fost goală (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Fulx RSS incompatibil"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1818,14 +1751,6 @@ msgstr "Serverul %s utilizează un certificat HTTPS nesigur"
msgid "RSS Feed %s was empty"
msgstr "Fluxul RSS %s a fost gol"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Fulx RSS incompatibil"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Valoare RSS gasită a fost goală (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Arată interfața"
@@ -3786,6 +3711,17 @@ msgstr ""
msgid "Enable"
msgstr "Activează"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4536,6 +4472,11 @@ msgstr "Şterge"
msgid "Filename"
msgstr "Nume de fișier"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Vârsta"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "Spațiu liber"
@@ -4964,6 +4905,10 @@ msgstr "Fișierul nu este pe server"
msgid "Server could not complete request"
msgstr ""
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Fişier NZB gol %s"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -3,12 +3,13 @@
#
# Translators:
# Safihre <safihre@sabnzbd.org>, 2023
# ST02, 2026
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Last-Translator: ST02, 2026\n"
"Language-Team: Russian (https://app.transifex.com/sabnzbd/teams/111101/ru/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -24,7 +25,7 @@ msgstr "Предупреждение"
#. Notification
#: SABnzbd.py, sabnzbd/notifier.py
msgid "Error"
msgstr ""
msgstr "Ошибка"
#. Error message
#: SABnzbd.py
@@ -88,7 +89,7 @@ msgstr ""
#. Error message
#: SABnzbd.py
msgid "HTTP and HTTPS ports cannot be the same"
msgstr ""
msgstr "HTTP и HTTPS порты не могут быть одинаковыми"
#. Warning message
#: SABnzbd.py
@@ -103,12 +104,12 @@ msgstr "HTTPS отключён, поскольку отсутствуют фай
#. Warning message
#: SABnzbd.py
msgid "Disabled HTTPS because of invalid CERT and KEY files"
msgstr ""
msgstr "HTTPS отключён, поскольку файлы CERT и KEY недействительны"
#. Error message
#: SABnzbd.py
msgid "Failed to start web-interface: "
msgstr ""
msgstr "Не удалось запустить веб-интерфейс:"
#: SABnzbd.py
msgid "SABnzbd %s started"
@@ -142,6 +143,11 @@ msgid ""
"creates."
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -301,7 +307,7 @@ msgstr ""
#: sabnzbd/assembler.py
msgid "Aborted, encryption detected"
msgstr ""
msgstr "Прервано, обнаружено шифрование"
#. Warning message
#: sabnzbd/assembler.py
@@ -312,9 +318,9 @@ msgstr ""
msgid "Unwanted extension is in rar file %s"
msgstr ""
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr ""
msgstr "Прервано, обнаружено нежелательное расширение"
#. Warning message
#: sabnzbd/assembler.py
@@ -343,7 +349,7 @@ msgstr ""
#: sabnzbd/bpsmeter.py
msgid "Downloading resumed after quota reset"
msgstr ""
msgstr "Загрузка возобновилась после сброса квоты"
#: sabnzbd/cfg.py, sabnzbd/interface.py
msgid "Incorrect parameter"
@@ -511,7 +517,7 @@ msgstr "Не удаётся прочитать наблюдаемую папку
#: sabnzbd/downloader.py
msgid "Resuming"
msgstr ""
msgstr "Возобновление"
#. PP status - Priority pick list
#: sabnzbd/downloader.py, sabnzbd/macosmenu.py, sabnzbd/sabtray.py,
@@ -728,6 +734,11 @@ msgid ""
"problems."
msgstr ""
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr ""
@@ -957,7 +968,7 @@ msgid "Update Available!"
msgstr "Доступно обновление!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr ""
@@ -1385,103 +1396,18 @@ msgstr "Ошибка загрузки %s: обнаружен повреждён
msgid "NZB added to queue"
msgstr "NZB-файл добавлен в очередь"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Пропущен повторяющийся NZB-файл «%s»"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Пустой NZB-файл %s"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr ""
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Ошибка импорта %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "ПОВТОР"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "ЗАШИФРОВАН"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "СЛИШКОМ БОЛЬШОЙ"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "НЕПОЛНЫЙ"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "ОЖИДАНИЕ %s с"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "Загружено за %s со средней скоростью %sБ/с"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Возраст"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s статей с ошибками"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s статей отсутствует"
#: sabnzbd/nzbstuff.py
msgid "%s articles had non-matching duplicates"
msgstr "%s статей содержат несовпадающие повторы"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Приостановлен повторяющийся NZB-файл «%s»"
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Проблема с"
@@ -1756,6 +1682,14 @@ msgstr "Не удалось завершить работу системы"
msgid "Received a DBus exception %s"
msgstr ""
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Обнаружена пустая запись RSS (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Несовместимая лента"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1782,14 +1716,6 @@ msgstr ""
msgid "RSS Feed %s was empty"
msgstr "RSS-лента %s была пустой"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Несовместимая лента"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Обнаружена пустая запись RSS (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Показать интерфейс"
@@ -3743,6 +3669,17 @@ msgstr ""
msgid "Enable"
msgstr "Включить"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4500,6 +4437,11 @@ msgstr "Удалить"
msgid "Filename"
msgstr "Название файла"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Возраст"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "свободно на диске"
@@ -4927,6 +4869,10 @@ msgstr ""
msgid "Server could not complete request"
msgstr ""
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Пустой NZB-файл %s"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\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"
@@ -140,6 +140,11 @@ msgid ""
"creates."
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -309,7 +314,7 @@ msgstr ""
msgid "Unwanted extension is in rar file %s"
msgstr "Neželjena ekstenzija je u rar datoteci %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "Prekinuto, detektovana neželjena ekstenzija"
@@ -726,6 +731,11 @@ msgid ""
"problems."
msgstr ""
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr ""
@@ -953,7 +963,7 @@ msgid "Update Available!"
msgstr "Нова верзија доступна!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr ""
@@ -1380,103 +1390,18 @@ msgstr "Грешка учитавање %s, покварена датотека
msgid "NZB added to queue"
msgstr "NZB додат у ред"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Игнорисање дуплог NZB-а \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Празан NZB %s"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "Поништено, не може да се заврши"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Грешка увоза %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "ДУПЛИКАТ"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "ШИФРИРАНО"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "ПРЕВЕЛИКО"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "НЕПОТПУНО"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "NEŽELJENI"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "Чекање %s сек"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "Преузето за %s на просек од %sБ/с"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Старост"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s артикла нису добро формирани"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s артикла недостају"
#: sabnzbd/nzbstuff.py
msgid "%s articles had non-matching duplicates"
msgstr "%s артикла нису дупликате"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Паузирам због дуплог NZB-а \"%s\""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Проблем са"
@@ -1749,6 +1674,14 @@ msgstr "Greška pri gašenju sistema"
msgid "Received a DBus exception %s"
msgstr ""
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Nađen prazan RSS unos (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Некомпатибилан Фид"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1775,14 +1708,6 @@ msgstr "Server %s koristi nepouzdan HTTPS sertifikat"
msgid "RSS Feed %s was empty"
msgstr "RSS фид %s је празан"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Некомпатибилан Фид"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Nađen prazan RSS unos (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Pokaži interfejs"
@@ -3729,6 +3654,17 @@ msgstr ""
msgid "Enable"
msgstr "Омогући"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4478,6 +4414,11 @@ msgstr "Обриши"
msgid "Filename"
msgstr "Име датотеке"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Старост"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "Слободан простор"
@@ -4904,6 +4845,10 @@ msgstr ""
msgid "Server could not complete request"
msgstr ""
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Празан NZB %s"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\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"
@@ -140,6 +140,11 @@ msgid ""
"creates."
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -309,7 +314,7 @@ msgstr ""
msgid "Unwanted extension is in rar file %s"
msgstr "Oönskad filändelse i RAR-fil %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "Avbruten, oönskad filändelse detekterad"
@@ -726,6 +731,11 @@ msgid ""
"problems."
msgstr ""
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr ""
@@ -955,7 +965,7 @@ msgid "Update Available!"
msgstr "Uppdatering tillgänglig"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr ""
@@ -1384,103 +1394,18 @@ msgstr "Laddningsfel %s, felaktig fil detekterad"
msgid "NZB added to queue"
msgstr "NZB tillagd i kön"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Ignorerar dubblett för NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr ""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "NZB filen %s är tom"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr ""
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "Avbrutet, kan inte slutföras"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "Det gick inte att importera %s"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "DUBLETT"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "KRYPTERAT"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "FÖR STOR"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "INKOMPLETT"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "OÖNSKAD"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "VÄNTA %s SEKUNDER"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr ""
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "Hämtade i %s vid ett genomsnitt på %sB/s"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Ålder"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s artiklar var felaktiga"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s artiklar saknades"
#: sabnzbd/nzbstuff.py
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\""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Problem med"
@@ -1755,6 +1680,14 @@ msgstr "Fel uppstod då systemet skulle stängas"
msgid "Received a DBus exception %s"
msgstr ""
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Tom RSS post hittades (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Inkompatibel feed"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1781,14 +1714,6 @@ msgstr "Server %s använder ett otillförlitlig HTTPS-certifikat"
msgid "RSS Feed %s was empty"
msgstr "RSS-flödet %s var tomt"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Inkompatibel feed"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Tom RSS post hittades (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Visa gränssnitt"
@@ -3741,6 +3666,17 @@ msgstr ""
msgid "Enable"
msgstr "Aktivera"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4491,6 +4427,11 @@ msgstr "Ta bort"
msgid "Filename"
msgstr "Filnamn"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Ålder"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "Ledigt diskutrymme"
@@ -4918,6 +4859,10 @@ msgstr ""
msgid "Server could not complete request"
msgstr ""
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "NZB filen %s är tom"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -3,14 +3,14 @@
#
# Translators:
# Taylan Tatlı, 2025
# mauron, 2025
# Safihre <safihre@sabnzbd.org>, 2025
# mauron, 2026
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\n"
"Last-Translator: mauron, 2026\n"
"Language-Team: Turkish (https://app.transifex.com/sabnzbd/teams/111101/tr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -151,6 +151,11 @@ msgstr ""
"Güncel umask (%o), SABnzbd'nin oluşturduğu dosya ve dizinlere erişimini "
"reddedebilir."
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr "SABnzbd'nin Windows ARM sürümü İndirmeler sayfamızda mevcuttur!"
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -342,7 +347,7 @@ msgstr ""
msgid "Unwanted extension is in rar file %s"
msgstr "İstenmeyen uzantı %s rar dosyasındadır"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "İptal edildi, istenmeyen uzantı tespit edildi"
@@ -777,6 +782,13 @@ msgid ""
msgstr ""
"%s özel karakterli dosya isimleri ile yazılamıyor. Bu, sorun oluşturabilir."
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
"%s aralıklı dosyaları desteklememektedir. Doğrudan yazma kipi devre dışı "
"bırakılıyor."
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Şuradan bağlantı reddedildi:"
@@ -1008,7 +1020,7 @@ msgid "Update Available!"
msgstr "Güncelleme Mevcut!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr "Dosyanın gönderilmesi başarısız oldu: %s"
@@ -1445,103 +1457,18 @@ msgstr "%s yüklenirken hata, bozuk dosya tespit edildi"
msgid "NZB added to queue"
msgstr "NZB kuyruğa ilave edildi"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "Yinelenmiş NZB \"%s\" dikkate alınmıyor"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr "\"%s\" NSB dosyasının yinelenmesi başarısız"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr "Yinelenmiş NZB"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr "Geçersiz NZB dosyası %s, atlanıyor (hata: %s)"
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Boş NZB dosyası %s"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr "Kuyruk öncesi betiği işi başarısız oldu olarak işaretlemiş"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr "%s (%s) dosyasında İstenmeyen Uzantı"
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "İptal edildi, tamamlanamıyor"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "%s unsurunun içe aktarılmasında hata"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "YİNELENMİŞ"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr "ALTERNATİF"
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "ŞİFRELENMİŞ"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "ÇOK BÜYÜK"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "TAMAMLANMAMIŞ"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "İSTENMEYEN"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "%s saniye BEKLEYİN"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr "YAYINLANIYOR %s dakika"
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "%s içinde ortalama %sB/s hızında indirildi"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "Yaş"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s makale yanlış şekillendirilmişti"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s makale eksikti"
#: sabnzbd/nzbstuff.py
msgid "%s articles had non-matching duplicates"
msgstr "%s makale eşleşmeyen yinelenmişler bulunduruyordu"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "Yinelenmiş NZB \"%s\" duraklatılıyor"
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "Şununla sorun"
@@ -1818,6 +1745,14 @@ msgstr "Sistemin kapatılması esnasında hata"
msgid "Received a DBus exception %s"
msgstr "Bir DBUS istisnası alındı %s"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Boş RSS girdisi bulundu (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Uyumsuz besleme"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1844,14 +1779,6 @@ msgstr "%s sunucusu güvenilmez bir HTTPS sertifikası kullanıyor"
msgid "RSS Feed %s was empty"
msgstr "%s RSS Beselemesi boştu"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "Uyumsuz besleme"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "Boş RSS girdisi bulundu (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "Arayüzü göster"
@@ -3461,6 +3388,8 @@ msgstr "SFV temelli kontrolleri etkinleştir"
msgid ""
"If no par2 files are available, use sfv files (if present) to verify files"
msgstr ""
"Eğer hiçbir par2 dosyası mevcut değilse, dosyaları kontrol etmek için "
"(mevcutsa) sfv dosyalarını kullan"
#: sabnzbd/skintext.py
msgid "User script can flag job as failed"
@@ -3881,6 +3810,20 @@ msgstr ""
msgid "Enable"
msgstr "Etkinleştir"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr "Talep başı makale"
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
"Her bir cevabı beklemeden bağlantı başına birden fazla makale talep et.<br "
"/>Bu, indirme hızlarını bilhassa yüksek gecikmeli bağlantılarda "
"arttırabilir."
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4661,6 +4604,11 @@ msgstr "Sil"
msgid "Filename"
msgstr "Dosya ismi"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "Yaş"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "Boş alan"
@@ -5100,6 +5048,10 @@ msgstr "Dosya sunucuda yok"
msgid "Server could not complete request"
msgstr "Sunucu talebi tamamlayamadı"
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "Boş NZB dosyası %s"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -8,7 +8,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\n"
"Language-Team: Chinese (China) (https://app.transifex.com/sabnzbd/teams/111101/zh_CN/)\n"
@@ -140,6 +140,11 @@ msgid ""
"creates."
msgstr "当前 umask (%o) 可能会拒绝 SABnzbd 访问其创建的文件和文件夹。"
#. Warning message
#: sabnzbd/__init__.py
msgid "Windows ARM version of SABnzbd is available from our Downloads page!"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid ""
@@ -310,7 +315,7 @@ msgstr "RAR 文件“%s”中出现不需要的扩展名。不需要的文件名
msgid "Unwanted extension is in rar file %s"
msgstr "rar 文件中出现不需要的扩展名 %s"
#: sabnzbd/assembler.py, sabnzbd/nzbstuff.py
#: sabnzbd/assembler.py
msgid "Aborted, unwanted extension detected"
msgstr "已中止,侦测到不需要的扩展名"
@@ -726,6 +731,11 @@ msgid ""
"problems."
msgstr "%s 不可写入带有特殊字符的文件名。这可能会导致问题。"
#. Warning message
#: sabnzbd/filesystem.py
msgid "%s does not support sparse files. Disabling direct write mode."
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "拒绝来自以下的连接:"
@@ -951,7 +961,7 @@ msgid "Update Available!"
msgstr "有更新可用!"
#. Error message
#: sabnzbd/misc.py
#: sabnzbd/misc.py, sabnzbd/skintext.py
msgid "Failed to upload file: %s"
msgstr "上传文件失败:%s"
@@ -1376,103 +1386,18 @@ msgstr "无法加载 %s侦测到损坏文件"
msgid "NZB added to queue"
msgstr "NZB 已添加到队列"
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Ignoring duplicate NZB \"%s\""
msgstr "正在忽略重复 NZB \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Failing duplicate NZB \"%s\""
msgstr "失败于重复的 NZB 文件 \"%s\""
#: sabnzbd/nzbqueue.py, sabnzbd/nzbstuff.py
#: sabnzbd/nzbqueue.py
msgid "Duplicate NZB"
msgstr "重复的 NZB 文件"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Invalid NZB file %s, skipping (error: %s)"
msgstr "无效的 NZB 文件 %s跳过错误%s"
#. Warning message
#: sabnzbd/nzbstuff.py, sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "空 NZB 文件 %s"
#: sabnzbd/nzbstuff.py
msgid "Pre-queue script marked job as failed"
msgstr "预队列脚本将任务标记为失败的"
#. Warning message
#: sabnzbd/nzbstuff.py
msgid "Unwanted Extension in file %s (%s)"
msgstr "文件 %s 中有不需要的扩展名 (%s)"
#: sabnzbd/nzbstuff.py
msgid "Aborted, cannot be completed"
msgstr "已中止,无法完成"
#. Error message
#: sabnzbd/nzbstuff.py
msgid "Error importing %s"
msgstr "导入 %s 出错"
#: sabnzbd/nzbstuff.py
msgid "DUPLICATE"
msgstr "*重复*"
#: sabnzbd/nzbstuff.py
msgid "ALTERNATIVE"
msgstr "备选"
#: sabnzbd/nzbstuff.py
msgid "ENCRYPTED"
msgstr "*加密*"
#: sabnzbd/nzbstuff.py
msgid "TOO LARGE"
msgstr "*太大*"
#: sabnzbd/nzbstuff.py
msgid "INCOMPLETE"
msgstr "*不完整*"
#: sabnzbd/nzbstuff.py
msgid "UNWANTED"
msgstr "不需要"
#: sabnzbd/nzbstuff.py
msgid "WAIT %s sec"
msgstr "*等待* %s 秒"
#: sabnzbd/nzbstuff.py
msgid "PROPAGATING %s min"
msgstr "传播延迟生效,等待 %s 分钟"
#: sabnzbd/nzbstuff.py
msgid "Downloaded in %s at an average of %sB/s"
msgstr "已下载,耗时 %s平均速度 %sB/s"
#. Job details page, file age column header
#: sabnzbd/nzbstuff.py, sabnzbd/skintext.py
msgid "Age"
msgstr "发布时间"
#: sabnzbd/nzbstuff.py
msgid "%s articles were malformed"
msgstr "%s 篇文章损坏"
#: sabnzbd/nzbstuff.py
msgid "%s articles were missing"
msgstr "%s 篇文章缺失"
#: sabnzbd/nzbstuff.py
msgid "%s articles had non-matching duplicates"
msgstr "%s 篇文章存在未匹配的重复"
#: sabnzbd/nzbstuff.py
msgid "Pausing duplicate NZB \"%s\""
msgstr "正在暂停重复 NZB \"%s\""
#: sabnzbd/panic.py
msgid "Problem with"
msgstr "问题"
@@ -1745,6 +1670,14 @@ msgstr "关闭系统时出错"
msgid "Received a DBus exception %s"
msgstr "收到 DBus 异常 %s"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "发现空的 RSS 条目 (%s)"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "feed 不兼容"
#. Error message
#: sabnzbd/rss.py
msgid "Incorrect RSS feed description \"%s\""
@@ -1771,14 +1704,6 @@ msgstr "服务器 %s 使用的 HTTPS 证书不受信任"
msgid "RSS Feed %s was empty"
msgstr "RSS Feed %s 为空"
#: sabnzbd/rss.py
msgid "Incompatible feed"
msgstr "feed 不兼容"
#: sabnzbd/rss.py
msgid "Empty RSS entry found (%s)"
msgstr "发现空的 RSS 条目 (%s)"
#: sabnzbd/sabtray.py, sabnzbd/sabtraylinux.py
msgid "Show interface"
msgstr "显示界面"
@@ -3690,6 +3615,17 @@ msgstr "对于不稳定的服务器,在失败后将会被忽略更长的时间
msgid "Enable"
msgstr "启用"
#: sabnzbd/skintext.py
msgid "Articles per request"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Request multiple articles per connection without waiting for each response "
"first.<br />This can improve download speeds, especially on connections with"
" higher latency."
msgstr ""
#. Button: Remove server
#: sabnzbd/skintext.py
msgid "Remove Server"
@@ -4442,6 +4378,11 @@ msgstr "删除"
msgid "Filename"
msgstr "文件名"
#. Job details page, file age column header
#: sabnzbd/skintext.py
msgid "Age"
msgstr "发布时间"
#: sabnzbd/skintext.py
msgid "Free Space"
msgstr "剩余空间"
@@ -4865,6 +4806,10 @@ msgstr "服务器上无此文件"
msgid "Server could not complete request"
msgstr "服务器无法完成请求"
#: sabnzbd/urlgrabber.py
msgid "Empty NZB file %s"
msgstr "空 NZB 文件 %s"
#. Error message
#: sabnzbd/urlgrabber.py
msgid "URLGRABBER CRASHED"

View File

@@ -1,10 +1,10 @@
#
# SABnzbd Translation Template file NSIS
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by The SABnzbd-Team (sabnzbd.org)
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\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

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\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.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\n"
"Language-Team: Danish (https://app.transifex.com/sabnzbd/teams/111101/da/)\n"

View File

@@ -8,7 +8,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\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.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\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.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\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.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\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.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\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.6.0\n"
"Project-Id-Version: SABnzbd-5.0.0\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2025\n"
"Language-Team: Italian (https://app.transifex.com/sabnzbd/teams/111101/it/)\n"

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,16 +1,17 @@
# Main requirements
# Note that not all sub-dependencies are listed, but only ones we know could cause trouble
apprise==1.9.6
sabctools==9.1.0
apprise==1.9.7
sabctools==9.3.1
CT3==3.4.0.post5
cffi==2.0.0
pycparser==2.23
pycparser # Version-less for Python 3.9 and below
pycparser==3.0; python_version > '3.9'
feedparser==6.0.12
configobj==5.0.9
cheroot==11.1.2
six==1.17.0
cherrypy==18.10.0
jaraco.functools==4.3.0
jaraco.functools==4.4.0
jaraco.collections==5.0.0
jaraco.text==3.8.1 # Newer version introduces irrelevant extra dependencies
jaraco.classes==3.4.0
@@ -32,12 +33,13 @@ 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==46.0.3
# Using older versions can have security implications!
cryptography>=3.0
# 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.11.0
orjson==3.11.5
orjson==3.11.7; python_version > '3.9'
# Windows system integration
pywin32==311; sys_platform == 'win32'
@@ -61,16 +63,16 @@ requests==2.32.5
requests-oauthlib==2.0.0
PyYAML==6.0.3
markdown # Version-less for Python 3.9 and below
markdown==3.10; python_version > '3.9'
markdown==3.10.1; python_version > '3.9'
paho-mqtt==1.6.1 # Pinned, newer versions don't work with AppRise yet
# Requests Requirements
charset_normalizer==3.4.4
idna==3.11
urllib3==2.6.0
certifi==2025.11.12
urllib3==2.6.3
certifi==2026.1.4
oauthlib==3.3.1
PyJWT==2.10.1
PyJWT==2.11.0
blinker==1.9.0
# Optional support for *nix tray icon.

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -32,11 +32,12 @@ from threading import Lock, Condition
# Determine platform flags
##############################################################################
WINDOWS = MACOS = MACOSARM64 = FOUNDATION = False
WINDOWS = WINDOWSARM64 = MACOS = MACOSARM64 = FOUNDATION = False
KERNEL32 = LIBC = MACOSLIBC = PLATFORM = None
if os.name == "nt":
WINDOWS = True
WINDOWSARM64 = platform.uname().machine == "ARM64"
if platform.uname().machine not in ["AMD64", "ARM64"]:
print("SABnzbd only supports 64-bit Windows")
@@ -82,15 +83,15 @@ from sabnzbd.version import __version__, __baseline__
import sabnzbd.misc as misc
import sabnzbd.filesystem as filesystem
import sabnzbd.powersup as powersup
import sabnzbd.rss as rss
import sabnzbd.emailer as emailer
import sabnzbd.encoding as encoding
import sabnzbd.config as config
import sabnzbd.cfg as cfg
import sabnzbd.database
import sabnzbd.lang as lang
import sabnzbd.nzb
import sabnzbd.nzbparser as nzbparser
import sabnzbd.nzbstuff
import sabnzbd.rss as rss
import sabnzbd.emailer as emailer
import sabnzbd.getipaddress
import sabnzbd.newsunpack
import sabnzbd.par2file
@@ -248,6 +249,7 @@ def initialize(pause_downloader=False, clean_up=False, repair=0):
# Set call backs for Config items
cfg.cache_limit.callback(cfg.new_limit)
cfg.direct_write.callback(cfg.new_direct_write)
cfg.web_host.callback(cfg.guard_restart)
cfg.web_port.callback(cfg.guard_restart)
cfg.web_dir.callback(cfg.guard_restart)
@@ -269,7 +271,6 @@ def initialize(pause_downloader=False, clean_up=False, repair=0):
cfg.language.callback(cfg.guard_language)
cfg.enable_https_verification.callback(cfg.guard_https_ver)
cfg.guard_https_ver()
cfg.pipelining_requests.callback(cfg.guard_restart)
# Set language files
lang.set_locale_info("SABnzbd", DIR_LANGUAGE)
@@ -303,6 +304,7 @@ def initialize(pause_downloader=False, clean_up=False, repair=0):
sabnzbd.NzbQueue.read_queue(repair)
sabnzbd.Scheduler.analyse(pause_downloader)
sabnzbd.ArticleCache.new_limit(cfg.cache_limit.get_int())
sabnzbd.Assembler.new_limit(sabnzbd.ArticleCache.cache_info().cache_limit)
logging.info("All processes started")
sabnzbd.RESTART_REQ = False
@@ -315,6 +317,9 @@ def start():
logging.debug("Starting postprocessor")
sabnzbd.PostProcessor.start()
logging.debug("Starting article cache")
sabnzbd.ArticleCache.start()
logging.debug("Starting assembler")
sabnzbd.Assembler.start()
@@ -383,6 +388,13 @@ def halt():
except Exception:
pass
logging.debug("Stopping article cache")
sabnzbd.ArticleCache.stop()
try:
sabnzbd.ArticleCache.join(timeout=3)
except Exception:
pass
logging.debug("Stopping postprocessor")
sabnzbd.PostProcessor.stop()
try:
@@ -482,6 +494,10 @@ def delayed_startup_actions():
sabnzbd.ORG_UMASK,
)
# Check if maybe we are running x64 version on ARM hardware
if sabnzbd.WINDOWSARM64 and "AMD64" in sys.version:
misc.helpful_warning(T("Windows ARM version of SABnzbd is available from our Downloads page!"))
# List the number of certificates available (can take up to 1.5 seconds)
if cfg.log_level() > 1:
logging.debug("Available certificates = %s", repr(ssl.create_default_context().cert_store_stats()))
@@ -496,7 +512,7 @@ def delayed_startup_actions():
logging.debug("Completed Download Folder %s is not on FAT", complete_dir)
if filesystem.directory_is_writable(sabnzbd.cfg.download_dir.get_path()):
filesystem.check_filesystem_capabilities(sabnzbd.cfg.download_dir.get_path())
filesystem.check_filesystem_capabilities(sabnzbd.cfg.download_dir.get_path(), is_download_dir=True)
if filesystem.directory_is_writable(sabnzbd.cfg.complete_dir.get_path()):
filesystem.check_filesystem_capabilities(sabnzbd.cfg.complete_dir.get_path())

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -20,6 +20,7 @@ sabnzbd.api - api
"""
import os
import sys
import logging
import re
import gc
@@ -57,6 +58,7 @@ from sabnzbd.constants import (
PP_LOOKUP,
STAGES,
DEF_NETWORKING_TEST_TIMEOUT,
DEF_PIPELINING_REQUESTS,
)
import sabnzbd.config as config
import sabnzbd.cfg as cfg
@@ -79,13 +81,14 @@ from sabnzbd.misc import (
clean_comma_separated_list,
match_str,
bool_conv,
get_platform_description,
)
from sabnzbd.filesystem import diskspace, get_ext, clip_path, remove_all, list_scripts, purge_log_files, pathbrowser
from sabnzbd.encoding import xml_name, utob
from sabnzbd.getipaddress import local_ipv4, public_ipv4, public_ipv6, dnslookup, active_socks5_proxy
from sabnzbd.database import HistoryDB
from sabnzbd.lang import is_rtl
from sabnzbd.nzbstuff import NzbObject
from sabnzbd.nzb import TryList, NzbObject
from sabnzbd.newswrapper import NewsWrapper, NNTPPermanentError
import sabnzbd.emailer
import sabnzbd.sorting
@@ -689,9 +692,16 @@ LOG_HASH_RE = re.compile(rb"([a-zA-Z\d]{25})", re.I)
def _api_showlog(name: str, kwargs: dict[str, Union[str, list[str]]]) -> bytes:
"""Fetch the INI and the log-data and add a message at the top"""
log_data = b"--------------------------------\n\n"
log_data += b"The log includes a copy of your sabnzbd.ini with\nall usernames, passwords and API-keys removed."
log_data += b"\n\n--------------------------------\n"
# Build header with version and environment info
header = "--------------------------------\n"
header += f"SABnzbd version: {sabnzbd.__version__}\n"
header += f"Commit: {sabnzbd.__baseline__}\n"
header += f"Python-version: {sys.version}\n"
header += f"Platform: {get_platform_description()}\n"
header += "--------------------------------\n\n"
header += "The log includes a copy of your sabnzbd.ini with\nall usernames, passwords and API-keys removed."
header += "\n\n--------------------------------\n"
log_data = header.encode("utf-8")
if sabnzbd.LOGFILE and os.path.exists(sabnzbd.LOGFILE):
with open(sabnzbd.LOGFILE, "rb") as f:
@@ -1006,7 +1016,7 @@ def _api_gc_stats(name: str, kwargs: dict[str, Union[str, list[str]]]) -> bytes:
# Collect before we check
gc.collect()
# We cannot create any lists/dicts, as they would create a reference
return report(data=[str(obj) for obj in gc.get_objects() if isinstance(obj, sabnzbd.nzbstuff.TryList)])
return report(data=[str(obj) for obj in gc.get_objects() if isinstance(obj, TryList)])
##############################################################################
@@ -1309,6 +1319,7 @@ def test_nntp_server_dict(kwargs: dict[str, Union[str, list[str]]]) -> tuple[boo
ssl = int_conv(kwargs.get("ssl", 0))
ssl_verify = int_conv(kwargs.get("ssl_verify", 3))
ssl_ciphers = kwargs.get("ssl_ciphers", "").strip()
pipelining_requests = int_conv(kwargs.get("pipelining_requests", DEF_PIPELINING_REQUESTS))
if not host:
return False, T("The hostname is not set.")
@@ -1345,6 +1356,7 @@ def test_nntp_server_dict(kwargs: dict[str, Union[str, list[str]]]) -> tuple[boo
use_ssl=ssl,
ssl_verify=ssl_verify,
ssl_ciphers=ssl_ciphers,
pipelining_requests=lambda: pipelining_requests,
username=username,
password=password,
)
@@ -1400,9 +1412,11 @@ def test_nntp_server_dict(kwargs: dict[str, Union[str, list[str]]]) -> tuple[boo
try:
nw.init_connect()
while not nw.connected:
while test_server.active:
nw.write()
nw.read(on_response=on_response)
if nw.ready:
break
except socket.timeout:
if port != 119 and not ssl:
@@ -1507,10 +1521,10 @@ def build_status(calculate_performance: bool = False, skip_dashboard: bool = Fal
info["servers"] = []
# Servers-list could be modified during iteration, so we need a copy
for server in sabnzbd.Downloader.servers[:]:
activeconn = sum(nw.connected for nw in server.idle_threads.copy())
activeconn = sum(nw.ready for nw in server.idle_threads.copy())
serverconnections = []
for nw in server.busy_threads.copy():
if nw.connected:
if nw.ready:
activeconn += 1
if article := nw.article:
serverconnections.append(

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -22,26 +22,39 @@ sabnzbd.articlecache - Article cache handling
import logging
import threading
import struct
from typing import Collection
import time
from typing import Collection, Optional
import sabnzbd
import sabnzbd.cfg as cfg
from sabnzbd.decorators import synchronized
from sabnzbd.constants import GIGI, ANFO, ASSEMBLER_WRITE_THRESHOLD
from sabnzbd.nzbstuff import Article
from sabnzbd.constants import (
GIGI,
ANFO,
ARTICLE_CACHE_NON_CONTIGUOUS_FLUSH_PERCENTAGE,
)
from sabnzbd.nzb import Article, NzbFile
from sabnzbd.misc import to_units
# Operations on the article table are handled via try/except.
# The counters need to be made atomic to ensure consistency.
ARTICLE_COUNTER_LOCK = threading.RLock()
_SECONDS_BETWEEN_FLUSHES = 0.5
class ArticleCache:
class ArticleCache(threading.Thread):
def __init__(self):
super().__init__()
self.shutdown = False
self.__direct_write: bool = bool(cfg.direct_write())
self.__cache_limit_org = 0
self.__cache_limit = 0
self.__cache_size = 0
self.__article_table: dict[Article, bytes] = {} # Dict of buffered articles
self.assembler_write_trigger: int = 1
self.__article_table: dict[Article, bytearray] = {} # Dict of buffered articles
self.__cache_size_cv: threading.Condition = threading.Condition(ARTICLE_COUNTER_LOCK)
self.__last_flush: float = 0
self.__non_contiguous_trigger: int = 0 # Force flush trigger
# On 32 bit we only allow the user to set 1GB
# For 64 bit we allow up to 4GB, in case somebody wants that
@@ -49,9 +62,62 @@ class ArticleCache:
if sabnzbd.MACOS or sabnzbd.WINDOWS or (struct.calcsize("P") * 8) == 64:
self.__cache_upper_limit = 4 * GIGI
def cache_info(self):
return ANFO(len(self.__article_table), abs(self.__cache_size), self.__cache_limit_org)
def change_direct_write(self, direct_write: bool) -> None:
self.__direct_write = direct_write and self.__cache_limit > 1
def stop(self):
self.shutdown = True
with self.__cache_size_cv:
self.__cache_size_cv.notify_all()
def should_flush(self) -> bool:
"""
Should we flush the cache?
Only if direct write is supported and cache usage is over the upper limit.
Or the downloader is paused and cache is not empty.
"""
return (
self.__direct_write
and self.__cache_limit
and (
self.__cache_size > self.__non_contiguous_trigger
or self.__cache_size
and sabnzbd.Downloader.no_active_jobs()
)
)
def flush_cache(self) -> None:
"""In direct_write mode flush cache contents to file"""
forced: set[NzbFile] = set()
for article in self.__article_table.copy():
if not article.can_direct_write or article.nzf in forced:
continue
forced.add(article.nzf)
if time.monotonic() - self.__last_flush > 1:
logging.debug("Forcing write of %s", article.nzf.filepath)
sabnzbd.Assembler.process(article.nzf.nzo, article.nzf, allow_non_contiguous=True, article=article)
self.__last_flush = time.monotonic()
def run(self):
while True:
with self.__cache_size_cv:
self.__cache_size_cv.wait_for(
lambda: self.shutdown or self.should_flush(),
timeout=5.0,
)
if self.shutdown:
break
# Could be reached by timeout when paused and no further articles arrive
with self.__cache_size_cv:
if not self.should_flush():
continue
self.flush_cache()
time.sleep(_SECONDS_BETWEEN_FLUSHES)
def cache_info(self):
return ANFO(len(self.__article_table), abs(self.__cache_size), self.__cache_limit)
@synchronized(ARTICLE_COUNTER_LOCK)
def new_limit(self, limit: int):
"""Called when cache limit changes"""
self.__cache_limit_org = limit
@@ -59,31 +125,32 @@ class ArticleCache:
self.__cache_limit = self.__cache_upper_limit
else:
self.__cache_limit = min(limit, self.__cache_upper_limit)
# Set assembler_write_trigger to be the equivalent of ASSEMBLER_WRITE_THRESHOLD %
# of the total cache, assuming an article size of 750 000 bytes
self.assembler_write_trigger = int(self.__cache_limit * ASSEMBLER_WRITE_THRESHOLD / 100 / 750_000) + 1
logging.debug(
"Assembler trigger = %d",
self.assembler_write_trigger,
)
self.__non_contiguous_trigger = self.__cache_limit * ARTICLE_CACHE_NON_CONTIGUOUS_FLUSH_PERCENTAGE
if self.__cache_limit:
logging.debug("Article cache trigger:%s", to_units(self.__non_contiguous_trigger))
self.change_direct_write(cfg.direct_write())
@synchronized(ARTICLE_COUNTER_LOCK)
def reserve_space(self, data_size: int):
def reserve_space(self, data_size: int) -> bool:
"""Reserve space in the cache"""
self.__cache_size += data_size
if (usage := self.__cache_size + data_size) > self.__cache_limit:
return False
self.__cache_size = usage
self.__cache_size_cv.notify_all()
return True
@synchronized(ARTICLE_COUNTER_LOCK)
def free_reserved_space(self, data_size: int):
"""Remove previously reserved space"""
self.__cache_size -= data_size
self.__cache_size_cv.notify_all()
@synchronized(ARTICLE_COUNTER_LOCK)
def space_left(self) -> bool:
"""Is there space left in the set limit?"""
return self.__cache_size < self.__cache_limit
def save_article(self, article: Article, data: bytes):
def save_article(self, article: Article, data: bytearray):
"""Save article in cache, either memory or disk"""
nzo = article.nzf.nzo
# Skip if already post-processing or fully finished
@@ -91,7 +158,8 @@ class ArticleCache:
return
# Register article for bookkeeping in case the job is deleted
nzo.saved_articles.add(article)
with nzo.lock:
nzo.saved_articles.add(article)
if article.lowest_partnum and not (article.nzf.import_finished or article.nzf.filename_checked):
# Write the first-fetched articles to temporary file unless downloading
@@ -100,24 +168,17 @@ class ArticleCache:
self.__flush_article_to_disk(article, data)
return
if self.__cache_limit:
# Check if we exceed the limit
data_size = len(data)
self.reserve_space(data_size)
if self.space_left():
# Add new article to the cache
self.__article_table[article] = data
else:
# Return the space and save to disk
self.free_reserved_space(data_size)
self.__flush_article_to_disk(article, data)
# Check if we exceed the limit
if self.__cache_limit and self.reserve_space(len(data)):
# Add new article to the cache
self.__article_table[article] = data
else:
# No data saved in memory, direct to disk
self.__flush_article_to_disk(article, data)
def load_article(self, article: Article):
def load_article(self, article: Article) -> Optional[bytearray]:
"""Load the data of the article"""
data = None
data: Optional[bytearray] = None
nzo = article.nzf.nzo
if article in self.__article_table:
@@ -131,9 +192,10 @@ class ArticleCache:
return data
elif article.art_id:
data = sabnzbd.filesystem.load_data(
article.art_id, nzo.admin_path, remove=True, do_pickle=False, silent=True
article.art_id, nzo.admin_path, remove=True, do_pickle=False, silent=True, mutable=True
)
nzo.saved_articles.discard(article)
with nzo.lock:
nzo.saved_articles.discard(article)
return data
def flush_articles(self):
@@ -161,10 +223,16 @@ class ArticleCache:
elif article.art_id:
sabnzbd.filesystem.remove_data(article.art_id, article.nzf.nzo.admin_path)
@staticmethod
def __flush_article_to_disk(article: Article, data):
def __flush_article_to_disk(self, article: Article, data: bytearray):
# Save data, but don't complain when destination folder is missing
# because this flush may come after completion of the NZO.
# Direct write to destination if cache is being used
if self.__cache_limit and self.__direct_write and sabnzbd.Assembler.assemble_article(article, data):
with article.nzf.nzo.lock:
article.nzf.nzo.saved_articles.discard(article)
return
# Fallback to disk cache
sabnzbd.filesystem.save_data(
data, article.get_art_id(), article.nzf.nzo.admin_path, do_pickle=False, silent=True
)

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -23,13 +23,16 @@ import os
import queue
import logging
import re
import threading
from threading import Thread
import ctypes
from typing import Optional
from typing import Optional, NamedTuple, Union
import rarfile
import time
import sabctools
import sabnzbd
from sabnzbd.misc import get_all_passwords, match_str, SABRarFile
from sabnzbd.misc import get_all_passwords, match_str, SABRarFile, to_units
from sabnzbd.filesystem import (
set_permissions,
clip_path,
@@ -39,33 +42,222 @@ from sabnzbd.filesystem import (
has_unwanted_extension,
get_basename,
)
from sabnzbd.constants import Status, GIGI
from sabnzbd.constants import (
Status,
GIGI,
ASSEMBLER_WRITE_THRESHOLD_FACTOR_APPEND,
ASSEMBLER_WRITE_THRESHOLD_FACTOR_DIRECT_WRITE,
ASSEMBLER_MAX_WRITE_THRESHOLD_DIRECT_WRITE,
SOFT_ASSEMBLER_QUEUE_LIMIT,
ASSEMBLER_DELAY_FACTOR_DIRECT_WRITE,
ARTICLE_CACHE_NON_CONTIGUOUS_FLUSH_PERCENTAGE,
ASSEMBLER_WRITE_INTERVAL,
)
import sabnzbd.cfg as cfg
from sabnzbd.nzbstuff import NzbObject, NzbFile
from sabnzbd.nzb import NzbFile, NzbObject, Article
import sabnzbd.par2file as par2file
class AssemblerTask(NamedTuple):
nzo: Optional[NzbObject] = None
nzf: Optional[NzbFile] = None
file_done: bool = False
allow_non_contiguous: bool = False
direct_write: bool = False
class Assembler(Thread):
def __init__(self):
super().__init__()
self.max_queue_size: int = cfg.assembler_max_queue_size()
self.queue: queue.Queue[tuple[Optional[NzbObject], Optional[NzbFile], Optional[bool]]] = queue.Queue()
self.direct_write: bool = cfg.direct_write()
self.cache_limit: int = 0
# Contiguous bytes required to trigger append writes
self.append_trigger: int = 1
# Total bytes required to trigger direct-write assembles
self.direct_write_trigger: int = 1
self.delay_trigger: int = 1
self.queue: queue.Queue[AssemblerTask] = queue.Queue()
self.queued_lock = threading.Lock()
self.queued_nzf: set[str] = set()
self.queued_nzf_non_contiguous: set[str] = set()
self.queued_next_time: dict[str, float] = dict()
self.ready_bytes_lock = threading.Lock()
self.ready_bytes: dict[str, int] = dict()
def stop(self):
self.queue.put((None, None, None))
self.queue.put(AssemblerTask())
def process(self, nzo: NzbObject, nzf: Optional[NzbFile] = None, file_done: Optional[bool] = None):
self.queue.put((nzo, nzf, file_done))
def new_limit(self, limit: int):
"""Called when cache limit changes"""
self.cache_limit = limit
self.append_trigger = max(1, int(limit * ASSEMBLER_WRITE_THRESHOLD_FACTOR_APPEND))
self.direct_write_trigger = max(
1,
min(
max(1, int(limit * ASSEMBLER_WRITE_THRESHOLD_FACTOR_DIRECT_WRITE)),
ASSEMBLER_MAX_WRITE_THRESHOLD_DIRECT_WRITE,
),
)
self.calculate_delay_trigger()
self.change_direct_write(cfg.direct_write())
logging.debug(
"Assembler trigger append=%s, direct=%s, delay=%s",
to_units(self.append_trigger),
to_units(self.direct_write_trigger),
to_units(self.delay_trigger),
)
def queue_level(self) -> float:
return self.queue.qsize() / self.max_queue_size
def change_direct_write(self, direct_write: bool) -> None:
self.direct_write = direct_write and self.direct_write_trigger > 1
self.calculate_delay_trigger()
def calculate_delay_trigger(self):
"""Point at which downloader should start being delayed, recalculated when cache limit or direct write changes"""
self.delay_trigger = int(
max(
(
750_000 * self.max_queue_size * ASSEMBLER_DELAY_FACTOR_DIRECT_WRITE
if self.direct_write
else 750_000 * self.max_queue_size
),
(
self.cache_limit * ARTICLE_CACHE_NON_CONTIGUOUS_FLUSH_PERCENTAGE
if self.direct_write
else min(self.append_trigger * self.max_queue_size, int(self.cache_limit * 0.5))
),
)
)
def is_busy(self) -> bool:
"""Returns True if the assembler thread has at least one NzbFile it is assembling"""
return bool(self.queued_nzf or self.queued_nzf_non_contiguous)
def total_ready_bytes(self) -> int:
with self.ready_bytes_lock:
return sum(self.ready_bytes.values())
def update_ready_bytes(self, nzf: NzbFile, delta: int) -> int:
with self.ready_bytes_lock:
cur = self.ready_bytes.get(nzf.nzf_id, 0) + delta
if cur <= 0:
self.ready_bytes.pop(nzf.nzf_id, None)
else:
self.ready_bytes[nzf.nzf_id] = cur
return cur
def clear_ready_bytes(self, *nzfs: NzbFile) -> None:
with self.ready_bytes_lock:
for nzf in nzfs:
self.ready_bytes.pop(nzf.nzf_id, None)
self.queued_next_time.pop(nzf.nzf_id, None)
def process(
self,
nzo: NzbObject = None,
nzf: Optional[NzbFile] = None,
file_done: bool = False,
allow_non_contiguous: bool = False,
article: Optional[Article] = None,
) -> None:
if nzf is None:
# post-proc
self.queue.put(AssemblerTask(nzo))
return
# Track bytes pending being written for this nzf
if self.should_track_ready_bytes(article, allow_non_contiguous):
ready_bytes = self.update_ready_bytes(nzf, article.decoded_size)
else:
ready_bytes = 0
article_has_first_part = bool(article and article.lowest_partnum)
if article_has_first_part:
self.queued_next_time[nzf.nzf_id] = time.monotonic() + ASSEMBLER_WRITE_INTERVAL
if not self.should_queue_nzf(
nzf,
article_has_first_part=article_has_first_part,
filename_checked=nzf.filename_checked,
import_finished=nzf.import_finished,
file_done=file_done,
allow_non_contiguous=allow_non_contiguous,
ready_bytes=ready_bytes,
):
return
with self.queued_lock:
# Recheck not already in the normal queue under lock, but always enqueue when file_done
if not file_done and nzf.nzf_id in self.queued_nzf:
return
if allow_non_contiguous:
if not file_done and nzf.nzf_id in self.queued_nzf_non_contiguous:
return
self.queued_nzf_non_contiguous.add(nzf.nzf_id)
else:
self.queued_nzf.add(nzf.nzf_id)
self.queued_next_time[nzf.nzf_id] = time.monotonic() + ASSEMBLER_WRITE_INTERVAL
can_direct_write = self.direct_write and nzf.type == "yenc"
self.queue.put(AssemblerTask(nzo, nzf, file_done, allow_non_contiguous, can_direct_write))
def should_queue_nzf(
self,
nzf: NzbFile,
*,
article_has_first_part: bool,
filename_checked: bool,
import_finished: bool,
file_done: bool,
allow_non_contiguous: bool,
ready_bytes: int,
) -> bool:
# Always queue if done
if file_done:
return True
if nzf.nzf_id in self.queued_nzf:
return False
# Always write
if article_has_first_part and filename_checked and not import_finished:
return True
next_ready = (next_article := nzf.assembler_next_article) and (next_article.decoded or next_article.on_disk)
# Trigger every 5 seconds if next article is decoded or on_disk
if next_ready and time.monotonic() > self.queued_next_time.get(nzf.nzf_id, 0):
return True
# Append
if not self.direct_write or nzf.type != "yenc":
return nzf.contiguous_ready_bytes() >= self.append_trigger
# Direct Write
if allow_non_contiguous:
return True
# Direct Write ready bytes trigger if next is also ready
if next_ready and ready_bytes >= self.direct_write_trigger:
return True
return False
@staticmethod
def should_track_ready_bytes(article: Optional[Article], allow_non_contiguous: bool) -> bool:
""""""
return article and not allow_non_contiguous and article.decoded_size
def delay(self) -> float:
"""Calculate how long if at all the downloader thread should sleep to allow the assembler to catch up"""
ready_total = self.total_ready_bytes()
# Below trigger: no delay possible
if ready_total <= self.delay_trigger:
return 0
pressure = (ready_total - self.delay_trigger) / max(1.0, self.cache_limit - self.delay_trigger)
if pressure <= SOFT_ASSEMBLER_QUEUE_LIMIT:
return 0
# 50-100%: 0-0.25 seconds, capped at 0.15
sleep = min((pressure - SOFT_ASSEMBLER_QUEUE_LIMIT) / 2, 0.15)
return max(0.001, sleep)
def run(self):
while 1:
# Set NzbObject and NzbFile objects to None so references
# from this thread do not keep the objects alive (see #1628)
nzo = nzf = None
nzo, nzf, file_done = self.queue.get()
nzo, nzf, file_done, allow_non_contiguous, direct_write = self.queue.get()
if not nzo:
logging.debug("Shutting down assembler")
break
@@ -75,11 +267,15 @@ class Assembler(Thread):
if file_done and not sabnzbd.Downloader.paused:
self.diskspace_check(nzo, nzf)
# Prepare filepath
if filepath := nzf.prepare_filepath():
try:
# Prepare filepath
if not (filepath := nzf.prepare_filepath()):
logging.debug("Prepare filepath failed for file %s in job %s", nzf.filename, nzo.final_name)
continue
try:
logging.debug("Decoding part of %s", filepath)
self.assemble(nzo, nzf, file_done)
self.assemble(nzo, nzf, file_done, allow_non_contiguous, direct_write)
# Continue after partly written data
if not file_done:
@@ -122,9 +318,16 @@ class Assembler(Thread):
except Exception:
logging.error(T("Fatal error in Assembler"), exc_info=True)
break
finally:
with self.queued_lock:
if allow_non_contiguous:
self.queued_nzf_non_contiguous.discard(nzf.nzf_id)
else:
self.queued_nzf.discard(nzf.nzf_id)
else:
sabnzbd.NzbQueue.remove(nzo.nzo_id, cleanup=False)
sabnzbd.PostProcessor.process(nzo)
self.clear_ready_bytes(*nzo.files)
@staticmethod
def diskspace_check(nzo: NzbObject, nzf: NzbFile):
@@ -162,52 +365,116 @@ class Assembler(Thread):
sabnzbd.emailer.diskfull_mail()
@staticmethod
def assemble(nzo: NzbObject, nzf: NzbFile, file_done: bool):
def assemble(nzo: NzbObject, nzf: NzbFile, file_done: bool, allow_non_contiguous: bool, direct_write: bool) -> None:
"""Assemble a NZF from its table of articles
1) Partial write: write what we have
2) Nothing written before: write all
"""
load_article = sabnzbd.ArticleCache.load_article
downloader = sabnzbd.Downloader
decodetable = nzf.decodetable
fd: Optional[int] = None
skipped: bool = False # have any articles been skipped
offset: int = 0 # sequential offset for append writes
try:
# Resume assembly from where we got to previously
for idx in range(nzf.assembler_next_index, len(decodetable)):
article = decodetable[idx]
# We write large article-sized chunks, so we can safely skip the buffering of Python
with open(nzf.filepath, "ab", buffering=0) as fout:
for article in nzf.decodetable:
# Break if deleted during writing
if nzo.status is Status.DELETED:
break
# allow_non_contiguous is when the cache forces the assembler to write all articles, even if it leaves gaps.
# In most cases we can stop at the first article that has not been tried, because they are requested in order.
# However, if we are paused then always consider the whole decodetable to ensure everything possible is written.
if allow_non_contiguous and not article.tries and not downloader.paused:
break
# Skip already written articles
if article.on_disk:
if fd is not None and article.decoded_size is not None:
# Move the file descriptor forward past this article
offset += article.decoded_size
if not skipped:
with nzf.lock:
if nzf.assembler_next_index == idx:
nzf.assembler_next_index = idx + 1
continue
# Write all decoded articles
if article.decoded:
# Could be empty in case nzo was deleted
if data := sabnzbd.ArticleCache.load_article(article):
written = fout.write(data)
# In raw/non-buffered mode fout.write may not write everything requested:
# https://docs.python.org/3/library/io.html?highlight=write#io.RawIOBase.write
while written < len(data):
written += fout.write(data[written:])
nzf.update_crc32(article.crc32, len(data))
article.on_disk = True
else:
logging.info("No data found when trying to write %s", article)
else:
# stop if next piece not yet decoded
if not article.decoded:
# If the article was not decoded but the file
# is done, it is just a missing piece, so keep writing
if file_done:
continue
# We reach an article that was not decoded
if allow_non_contiguous:
skipped = True
continue
break
# Could be empty in case nzo was deleted
data = load_article(article)
if not data:
if file_done:
continue
if allow_non_contiguous:
skipped = True
continue
else:
# We reach an article that was not decoded
logging.info("No data found when trying to write %s", article)
break
# If required open the file
if fd is None:
fd, offset, direct_write = Assembler.open(
nzf, direct_write and article.can_direct_write, article.file_size
)
if not direct_write and allow_non_contiguous:
# Can only be allow_non_contiguous if we wanted direct_write, file_done will always be queued separately
break
if direct_write and article.can_direct_write:
offset += Assembler.write(fd, idx, nzf, article, data)
else:
if direct_write and skipped and not file_done:
# If we have already skipped an article then need to abort, unless this is the final assemble
break
offset += Assembler.write(fd, idx, nzf, article, data, offset)
finally:
if fd is not None:
os.close(fd)
# Final steps
if file_done:
sabnzbd.Assembler.clear_ready_bytes(nzf)
set_permissions(nzf.filepath)
nzf.assembled = True
@staticmethod
def assemble_article(article: Article, data: bytearray) -> bool:
"""Write a single article to disk"""
if not article.can_direct_write:
return False
nzf = article.nzf
with nzf.file_lock:
fd, _, direct_write = Assembler.open(nzf, True, article.file_size)
try:
if not direct_write:
cfg.direct_write.set(False)
return False
Assembler.write(fd, None, nzf, article, data)
except FileNotFoundError:
# nzo has probably been deleted, ArticleCache tries the fallback and handles it
return False
finally:
os.close(fd)
return True
@staticmethod
def check_encrypted_and_unwanted(nzo: NzbObject, nzf: NzbFile):
"""Encryption and unwanted extension detection"""
@@ -245,6 +512,71 @@ class Assembler(Thread):
nzo.fail_msg = T("Aborted, unwanted extension detected")
sabnzbd.NzbQueue.end_job(nzo)
@staticmethod
def write(
fd: int, nzf_index: Optional[int], nzf: NzbFile, article: Article, data: bytearray, offset: Optional[int] = None
) -> int:
"""Write data at position in a file"""
pos = article.data_begin if offset is None else offset
written = Assembler._write(fd, nzf, data, pos)
# In raw/non-buffered mode os.write may not write everything requested:
# https://docs.python.org/3/library/io.html?highlight=write#io.RawIOBase.write
if written < len(data) and (mv := memoryview(data)):
while written < len(data):
written += Assembler._write(fd, nzf, mv[written:], pos + written)
nzf.update_crc32(article.crc32, len(data))
article.on_disk = True
sabnzbd.Assembler.update_ready_bytes(nzf, -len(data))
with nzf.lock:
# assembler_next_index is the lowest index that has not yet been written sequentially from the start of the file.
# If this was the next required index to remain sequential, it can be incremented which allows the assembler to
# resume without rechecking articles that are already known to be on disk.
# If nzf_index is None, determine it now.
if nzf_index is None:
idx = nzf.assembler_next_index
if idx < len(nzf.decodetable) and article == nzf.decodetable[idx]:
nzf_index = idx
if nzf_index is not None and nzf.assembler_next_index == nzf_index:
nzf.assembler_next_index += 1
return written
@staticmethod
def _write(fd: int, nzf: NzbFile, data: Union[bytearray, memoryview], offset: int) -> int:
if sabnzbd.WINDOWS:
# pwrite is not implemented on Windows so fallback to os.lseek and os.write
# Must lock since it is possible to write from multiple threads (assembler + downloader)
with nzf.file_lock:
os.lseek(fd, offset, os.SEEK_SET)
return os.write(fd, data)
else:
return os.pwrite(fd, data, offset)
@staticmethod
def open(nzf: NzbFile, direct_write: bool, file_size: int) -> tuple[int, int, bool]:
"""Open file for nzf
Use direct_write if requested, with a fallback to setting the current file position for append mode
:returns (file_descriptor, current_offset, can_direct_write)
"""
with nzf.file_lock:
# Get the current umask without changing it, to create a file with the same permissions as `with open(...)`
os.umask(os.umask(0))
fd = os.open(nzf.filepath, os.O_CREAT | os.O_WRONLY | getattr(os, "O_BINARY", 0), 0o666)
offset = nzf.contiguous_offset()
os.lseek(fd, offset, os.SEEK_SET)
if direct_write:
if not file_size:
direct_write = False
if os.fstat(fd).st_size == 0:
try:
sabctools.sparse(fd, file_size)
except OSError:
logging.debug("Sparse call failed for %s", nzf.filepath)
cfg.direct_write.set(False)
direct_write = False
return fd, offset, direct_write
RE_SUBS = re.compile(r"\W+sub|subs|subpack|subtitle|subtitles(?![a-z])", re.I)
SAFE_EXTS = (".mkv", ".mp4", ".avi", ".wmv", ".mpg", ".webm")

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -25,6 +25,7 @@ import re
import argparse
import socket
import ipaddress
import threading
from typing import Union
import sabnzbd
@@ -508,6 +509,7 @@ x_frame_options = OptionBool("misc", "x_frame_options", True)
allow_old_ssl_tls = OptionBool("misc", "allow_old_ssl_tls", False)
enable_season_sorting = OptionBool("misc", "enable_season_sorting", True)
verify_xff_header = OptionBool("misc", "verify_xff_header", True)
direct_write = OptionBool("misc", "direct_write", True)
# Text values
rss_odd_titles = OptionList("misc", "rss_odd_titles", ["nzbindex.nl/", "nzbindex.com/", "nzbclub.com/"])
@@ -535,7 +537,6 @@ ssdp_broadcast_interval = OptionNumber("misc", "ssdp_broadcast_interval", 15, mi
ext_rename_ignore = OptionList("misc", "ext_rename_ignore", validation=lower_case_ext)
unrar_parameters = OptionStr("misc", "unrar_parameters", validation=supported_unrar_parameters)
outgoing_nntp_ip = OptionStr("misc", "outgoing_nntp_ip")
pipelining_requests = OptionNumber("misc", "pipelining_requests", DEF_PIPELINING_REQUESTS, minval=1, maxval=10)
##############################################################################
@@ -744,6 +745,13 @@ def new_limit():
if sabnzbd.__INITIALIZED__:
# Only update after full startup
sabnzbd.ArticleCache.new_limit(cache_limit.get_int())
sabnzbd.Assembler.new_limit(sabnzbd.ArticleCache.cache_info().cache_limit)
def new_direct_write():
"""Callback for direct write changes"""
sabnzbd.Assembler.change_direct_write(bool(direct_write()))
sabnzbd.ArticleCache.change_direct_write(bool(direct_write()))
def guard_restart():

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -42,6 +42,7 @@ from sabnzbd.constants import (
CONFIG_BACKUP_HTTPS,
DEF_INI_FILE,
DEF_SORTER_RENAME_SIZE,
DEF_PIPELINING_REQUESTS,
)
from sabnzbd.decorators import synchronized
from sabnzbd.filesystem import clip_path, real_path, create_real_path, renamer, remove_file, is_writable
@@ -209,7 +210,8 @@ class OptionBool(Option):
super().set(sabnzbd.misc.bool_conv(value))
def __call__(self) -> int:
"""get() replacement"""
"""Many places assume 0/1 is used for historical reasons.
Using pure bools breaks in random places"""
return int(self.get())
@@ -444,6 +446,7 @@ class ConfigServer:
self.enable = OptionBool(name, "enable", True, add=False)
self.required = OptionBool(name, "required", False, add=False)
self.optional = OptionBool(name, "optional", False, add=False)
self.pipelining_requests = OptionNumber(name, "pipelining_requests", DEF_PIPELINING_REQUESTS, 1, 20, add=False)
self.retention = OptionNumber(name, "retention", 0, add=False)
self.expire_date = OptionStr(name, "expire_date", add=False)
self.quota = OptionStr(name, "quota", add=False)
@@ -476,6 +479,7 @@ class ConfigServer:
"enable",
"required",
"optional",
"pipelining_requests",
"retention",
"expire_date",
"quota",
@@ -511,6 +515,7 @@ class ConfigServer:
output_dict["enable"] = self.enable()
output_dict["required"] = self.required()
output_dict["optional"] = self.optional()
output_dict["pipelining_requests"] = self.pipelining_requests()
output_dict["retention"] = self.retention()
output_dict["expire_date"] = self.expire_date()
output_dict["quota"] = self.quota()

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -50,7 +50,7 @@ RENAMES_FILE = "__renames__"
ATTRIB_FILE = "SABnzbd_attrib"
REPAIR_REQUEST = "repair-all.sab"
SABCTOOLS_VERSION_REQUIRED = "9.1.0"
SABCTOOLS_VERSION_REQUIRED = "9.3.1"
DB_HISTORY_VERSION = 1
DB_HISTORY_NAME = "history%s.db" % DB_HISTORY_VERSION
@@ -100,10 +100,16 @@ CONFIG_BACKUP_HTTPS = { # "basename": "associated setting"
DEF_MAX_ASSEMBLER_QUEUE = 12
SOFT_ASSEMBLER_QUEUE_LIMIT = 0.5
# Percentage of cache to use before adding file to assembler
ASSEMBLER_WRITE_THRESHOLD = 5
ASSEMBLER_WRITE_THRESHOLD_FACTOR_APPEND = 0.05
ASSEMBLER_WRITE_THRESHOLD_FACTOR_DIRECT_WRITE = 0.75
ASSEMBLER_MAX_WRITE_THRESHOLD_DIRECT_WRITE = int(1 * GIGI)
ASSEMBLER_DELAY_FACTOR_DIRECT_WRITE = 1.5
ASSEMBLER_WRITE_INTERVAL = 5.0
NNTP_BUFFER_SIZE = int(256 * KIBI)
NTTP_MAX_BUFFER_SIZE = int(10 * MEBI)
DEF_PIPELINING_REQUESTS = 2
DEF_PIPELINING_REQUESTS = 1
# Article cache capacity factor to force a non-contiguous flush to disk
ARTICLE_CACHE_NON_CONTIGUOUS_FLUSH_PERCENTAGE = 0.9
REPAIR_PRIORITY = 3
FORCE_PRIORITY = 2

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -114,6 +114,12 @@ class HistoryDB:
_ = self.execute("PRAGMA user_version = 5;") and self.execute(
"ALTER TABLE history ADD COLUMN time_added INTEGER;"
)
if version < 6:
_ = (
self.execute("PRAGMA user_version = 6;")
and self.execute("CREATE UNIQUE INDEX idx_history_nzo_id ON history(nzo_id);")
and self.execute("CREATE INDEX idx_history_archive_completed ON history(archive, completed DESC);")
)
HistoryDB.startup_done = True
@@ -160,8 +166,7 @@ class HistoryDB:
def create_history_db(self):
"""Create a new (empty) database file"""
self.execute(
"""
self.execute("""
CREATE TABLE history (
"id" INTEGER PRIMARY KEY,
"completed" INTEGER NOT NULL,
@@ -194,9 +199,10 @@ class HistoryDB:
"archive" INTEGER,
"time_added" INTEGER
)
"""
)
self.execute("PRAGMA user_version = 5;")
""")
self.execute("PRAGMA user_version = 6;")
self.execute("CREATE UNIQUE INDEX idx_history_nzo_id ON history(nzo_id);")
self.execute("CREATE INDEX idx_history_archive_completed ON history(archive, completed DESC);")
def close(self):
"""Close database connection"""
@@ -369,33 +375,34 @@ class HistoryDB:
def have_duplicate_key(self, duplicate_key: str) -> bool:
"""Check whether History contains this duplicate key"""
total = 0
if self.execute(
"""
SELECT COUNT(*)
FROM History
WHERE
duplicate_key = ? AND
STATUS != ?""",
SELECT EXISTS(
SELECT 1
FROM history
WHERE duplicate_key = ? AND status != ?
) as found
""",
(duplicate_key, Status.FAILED),
):
total = self.cursor.fetchone()["COUNT(*)"]
return total > 0
return bool(self.cursor.fetchone()["found"])
return False
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 EXISTS(
SELECT 1
FROM history
WHERE (name = ? COLLATE NOCASE OR md5sum = ?)
AND status != ?
) as found
""",
(name, md5sum, Status.FAILED),
):
total = self.cursor.fetchone()["COUNT(*)"]
return total > 0
return bool(self.cursor.fetchone()["found"])
return False
def get_history_size(self) -> tuple[int, int, int]:
"""Returns the total size of the history and
@@ -498,9 +505,14 @@ def convert_search(search: str) -> str:
return search
def build_history_info(nzo, workdir_complete: str, postproc_time: int, script_output: str, script_line: str):
def build_history_info(
nzo: "sabnzbd.nzb.NzbObject",
workdir_complete: str,
postproc_time: int,
script_output: str,
script_line: str,
):
"""Collects all the information needed for the database"""
nzo: sabnzbd.nzbstuff.NzbObject
completed = int(time.time())
pp = PP_LOOKUP.get(opts_to_pp(nzo.repair, nzo.unpack, nzo.delete), "X")

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -25,7 +25,7 @@ from typing import Optional
import sabnzbd
from sabnzbd.constants import SABCTOOLS_VERSION_REQUIRED
from sabnzbd.nzbstuff import Article
from sabnzbd.nzb import Article
from sabnzbd.misc import match_str
# Check for correct SABCTools version
@@ -163,6 +163,7 @@ def decode_yenc(article: Article, response: sabctools.NNTPResponse) -> bytearray
article.file_size = response.file_size
article.data_begin = response.part_begin
article.data_size = response.part_size
article.decoded_size = response.bytes_decoded
nzf = article.nzf
# Assume it is yenc
@@ -198,6 +199,7 @@ def decode_uu(article: Article, response: sabctools.NNTPResponse) -> bytearray:
raise BadData(response.data)
decoded_data = response.data
article.decoded_size = response.bytes_decoded
nzf = article.nzf
nzf.type = "uu"

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -20,10 +20,9 @@
##############################################################################
import time
import functools
from typing import Union, Callable
from typing import Union, Callable, Any
from threading import Lock, RLock, Condition
# All operations that modify the queue need to happen in a lock
# Also used when importing NZBs to prevent IO-race conditions
# Names of wrapper-functions should be the same in misc.caller_name
@@ -35,15 +34,21 @@ DOWNLOADER_CV = Condition(NZBQUEUE_LOCK)
DOWNLOADER_LOCK = RLock()
def synchronized(lock: Union[Lock, RLock]):
def synchronized(lock: Union[Lock, RLock, Condition, None] = None):
def wrap(func: Callable):
def call_func(*args, **kw):
# Using the try/finally approach is 25% faster compared to using "with lock"
# Either use the supplied lock or the object-specific one
# Because it's a variable in the upper function, we cannot use it directly
lock_obj = lock
if not lock_obj:
lock_obj = getattr(args[0], "lock")
# Using try/finally is ~25% faster than "with lock"
try:
lock.acquire()
lock_obj.acquire()
return func(*args, **kw)
finally:
lock.release()
lock_obj.release()
return call_func
@@ -81,6 +86,9 @@ def conditional_cache(cache_time: int):
def wrapper(*args, **kwargs):
current_time = time.time()
# Exclude force from the cache key
force = kwargs.pop("force", False)
# Create cache key using functools._make_key
try:
key = functools._make_key(args, kwargs, typed=False)
@@ -90,15 +98,16 @@ def conditional_cache(cache_time: int):
# If args/kwargs aren't hashable, skip caching entirely
return func(*args, **kwargs)
# Allow force kward to skip cache
if not kwargs.get("force"):
# Allow force kwarg to skip cache
if not force:
# Check if we have a valid cached result
if key in cache:
cached_result, timestamp = cache[key]
if current_time - timestamp < cache_time:
entry = cache.get(key)
if entry is not None:
cached_result, expires_at = entry
if current_time < expires_at:
return cached_result
# Cache entry expired, remove it
del cache[key]
cache.pop(key, None)
# Call the original function
result = func(*args, **kwargs)
@@ -106,7 +115,7 @@ def conditional_cache(cache_time: int):
# Only cache non-empty results
# This excludes None, [], {}, "", 0, False, etc.
if result:
cache[key] = (result, current_time)
cache[key] = (result, current_time + cache_time)
return result

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -27,6 +27,7 @@ files to the job-name in the queue if the filename looks obfuscated
Based on work by P1nGu1n
"""
import hashlib
import logging
import os
@@ -189,7 +190,7 @@ def get_biggest_file(filelist: list[str]) -> str:
return None
def deobfuscate(nzo, filelist: list[str], usefulname: str) -> list[str]:
def deobfuscate(nzo: "sabnzbd.nzb.NzbObject", filelist: list[str], usefulname: str) -> list[str]:
"""
For files in filelist:
1. if a file has no meaningful extension, add it (for example ".txt" or ".png")
@@ -227,9 +228,6 @@ def deobfuscate(nzo, filelist: list[str], usefulname: str) -> list[str]:
"""
# Can't be imported directly due to circular import
nzo: sabnzbd.nzbstuff.NzbObject
# to be sure, only keep really existing files and remove any duplicates:
filtered_filelist = list(set(f for f in filelist if os.path.isfile(f)))
@@ -320,7 +318,7 @@ def without_extension(fullpathfilename: str) -> str:
return os.path.splitext(fullpathfilename)[0]
def deobfuscate_subtitles(nzo, filelist: list[str]):
def deobfuscate_subtitles(nzo: "sabnzbd.nzb.NzbObject", filelist: list[str]):
"""
input:
nzo, so we can update result via set_unpack_info()
@@ -345,10 +343,6 @@ def deobfuscate_subtitles(nzo, filelist: list[str]):
Something.else.txt
"""
# Can't be imported directly due to circular import
nzo: sabnzbd.nzbstuff.NzbObject
# find .srt files
if not (srt_files := [f for f in filelist if f.endswith(".srt")]):
logging.debug("No .srt files found, so nothing to do")

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -31,7 +31,7 @@ import sabnzbd
import sabnzbd.cfg as cfg
from sabnzbd.misc import int_conv, format_time_string, build_and_run_command
from sabnzbd.filesystem import remove_all, real_path, remove_file, get_basename, clip_path
from sabnzbd.nzbstuff import NzbObject, NzbFile
from sabnzbd.nzb import NzbFile, NzbObject
from sabnzbd.encoding import platform_btou
from sabnzbd.decorators import synchronized
from sabnzbd.newsunpack import RAR_EXTRACTFROM_RE, RAR_EXTRACTED_RE, rar_volumelist, add_time_left

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -28,7 +28,7 @@ import sys
import ssl
import time
from datetime import date
from typing import Optional, Union, Deque
from typing import Optional, Union, Deque, Callable
import sabctools
@@ -37,10 +37,8 @@ from sabnzbd.decorators import synchronized, NzbQueueLocker, DOWNLOADER_CV, DOWN
from sabnzbd.newswrapper import NewsWrapper, NNTPPermanentError
import sabnzbd.config as config
import sabnzbd.cfg as cfg
from sabnzbd.misc import from_units, helpful_warning, int_conv, MultiAddQueue
from sabnzbd.misc import from_units, helpful_warning, int_conv, MultiAddQueue, to_units
from sabnzbd.get_addrinfo import get_fastest_addrinfo, AddrInfo
from sabnzbd.constants import SOFT_ASSEMBLER_QUEUE_LIMIT
# Timeout penalty in minutes for each cause
_PENALTY_UNKNOWN = 3 # Unknown cause
@@ -85,6 +83,7 @@ class Server:
"retention",
"username",
"password",
"pipelining_requests",
"busy_threads",
"next_busy_threads_check",
"idle_threads",
@@ -113,6 +112,7 @@ class Server:
use_ssl,
ssl_verify,
ssl_ciphers,
pipelining_requests,
username=None,
password=None,
required=False,
@@ -137,6 +137,7 @@ class Server:
self.retention: int = retention
self.username: Optional[str] = username
self.password: Optional[str] = password
self.pipelining_requests: Callable[[], int] = pipelining_requests
self.busy_threads: set[NewsWrapper] = set()
self.next_busy_threads_check: float = 0
@@ -151,7 +152,7 @@ class Server:
self.request: bool = False # True if a getaddrinfo() request is pending
self.have_body: bool = True # Assume server has "BODY", until proven otherwise
self.have_stat: bool = True # Assume server has "STAT", until proven otherwise
self.article_queue: Deque[sabnzbd.nzbstuff.Article] = deque()
self.article_queue: Deque[sabnzbd.nzb.Article] = deque()
# Skip during server testing
if threads:
@@ -170,7 +171,6 @@ class Server:
def stop(self):
"""Remove all connections and cached articles from server"""
for nw in self.idle_threads:
sabnzbd.Downloader.remove_socket(nw)
nw.hard_reset()
self.idle_threads = set()
self.reset_article_queue()
@@ -188,8 +188,12 @@ class Server:
if self.article_queue:
article = self.article_queue[0] if peek else self.article_queue.popleft()
# Mark expired articles as tried on this server
if not peek and self.retention and article.nzf.nzo.avg_stamp < time.time() - self.retention:
sabnzbd.Downloader.decode(article)
if self.retention and article.nzf.nzo.avg_stamp < time.time() - self.retention:
if not peek:
sabnzbd.Downloader.decode(article)
# sabnzbd.NzbQueue.get_articles stops after each nzo with articles.
# As a result, if one article is out of retention, all remaining
# entries in article_queue will also be out of retention.
while self.article_queue:
sabnzbd.Downloader.decode(self.article_queue.pop())
else:
@@ -296,7 +300,12 @@ class Downloader(Thread):
self.force_disconnect: bool = False
self.selector: selectors.DefaultSelector = selectors.DefaultSelector()
# macOS/BSD will default to KqueueSelector, it's very efficient but produces separate events for READ and WRITE.
# Which causes problems when two receive threads are both trying to use the connection while it is resetting.
if selectors.DefaultSelector is getattr(selectors, "KqueueSelector", None):
self.selector: selectors.BaseSelector = selectors.PollSelector()
else:
self.selector: selectors.BaseSelector = selectors.DefaultSelector()
self.servers: list[Server] = []
self.timers: dict[str, list[float]] = {}
@@ -325,6 +334,7 @@ class Downloader(Thread):
ssl = srv.ssl()
ssl_verify = srv.ssl_verify()
ssl_ciphers = srv.ssl_ciphers()
pipelining_requests = srv.pipelining_requests
username = srv.username()
password = srv.password()
required = srv.required()
@@ -355,6 +365,7 @@ class Downloader(Thread):
ssl,
ssl_verify,
ssl_ciphers,
pipelining_requests,
username,
password,
required,
@@ -370,6 +381,8 @@ class Downloader(Thread):
def add_socket(self, nw: NewsWrapper):
"""Add a socket to be watched for read or write availability"""
if nw.nntp:
nw.server.idle_threads.discard(nw)
nw.server.busy_threads.add(nw)
try:
self.selector.register(nw.nntp.fileno, selectors.EVENT_READ | selectors.EVENT_WRITE, nw)
nw.selector_events = selectors.EVENT_READ | selectors.EVENT_WRITE
@@ -379,7 +392,7 @@ class Downloader(Thread):
@synchronized(DOWNLOADER_LOCK)
def modify_socket(self, nw: NewsWrapper, events: int):
"""Modify the events socket are watched for"""
if nw.nntp and nw.selector_events != events:
if nw.nntp and nw.selector_events != events and not nw.blocking:
try:
self.selector.modify(nw.nntp.fileno, events, nw)
nw.selector_events = events
@@ -390,6 +403,9 @@ class Downloader(Thread):
def remove_socket(self, nw: NewsWrapper):
"""Remove a socket to be watched"""
if nw.nntp:
nw.server.busy_threads.discard(nw)
nw.server.idle_threads.add(nw)
nw.timeout = None
try:
self.selector.unregister(nw.nntp.fileno)
nw.selector_events = 0
@@ -540,7 +556,7 @@ class Downloader(Thread):
server.addrinfo = None
@staticmethod
def decode(article: "sabnzbd.nzbstuff.Article", response: Optional[sabctools.NNTPResponse] = None):
def decode(article: "sabnzbd.nzb.Article", response: Optional[sabctools.NNTPResponse] = None):
"""Decode article"""
# Need a better way of draining requests
if article.nzf.nzo.removed_from_queue:
@@ -644,12 +660,12 @@ class Downloader(Thread):
if not server.get_article(peek=True):
break
server.idle_threads.remove(nw)
server.busy_threads.add(nw)
if nw.connected:
# Assign a request immediately if NewsWrapper is ready, if we wait until the socket is
# selected all idle connections will be activated when there may only be one request
nw.prepare_request()
self.add_socket(nw)
else:
elif not nw.nntp:
try:
logging.info("%s@%s: Initiating connection", nw.thrdnum, server.host)
nw.init_connect()
@@ -694,7 +710,8 @@ class Downloader(Thread):
if self.selector.get_map():
if events := self.selector.select(timeout=1.0):
for key, ev in events:
process_nw_queue.put((key.data, ev))
nw = key.data
process_nw_queue.put((nw, ev, nw.generation))
else:
events = []
BPSMeter.reset()
@@ -738,23 +755,48 @@ class Downloader(Thread):
logging.error(T("Fatal error in Downloader"), exc_info=True)
self.pause()
def process_nw(self, nw: NewsWrapper, event: int):
def process_nw(self, nw: NewsWrapper, event: int, generation: int):
"""Receive data from a NewsWrapper and handle the response"""
if event & selectors.EVENT_READ:
self.process_nw_read(nw)
if event & selectors.EVENT_WRITE:
# Drop stale items
if nw.generation != generation:
return
# Read on EVENT_READ, or on EVENT_WRITE if TLS needs a write to complete a read
if (event & selectors.EVENT_READ) or (event & selectors.EVENT_WRITE and nw.tls_wants_write):
self.process_nw_read(nw, generation)
# If read caused a reset, don't proceed to write
if nw.generation != generation:
return
# The read may have removed the socket, so prevent calling prepare_request again
if not (nw.selector_events & selectors.EVENT_WRITE):
return
# Only attempt app-level writes if TLS is not blocked
if (event & selectors.EVENT_WRITE) and not nw.tls_wants_write:
nw.write()
def process_nw_read(self, nw: NewsWrapper) -> None:
def process_nw_read(self, nw: NewsWrapper, generation: int) -> None:
bytes_received: int = 0
bytes_pending: int = 0
while True:
while (
nw.connected
and nw.generation == generation
and not self.force_disconnect
and not self.shutdown
and not (nw.timeout and time.time() > nw.timeout)
):
try:
n, bytes_pending = nw.read(nbytes=bytes_pending)
n, bytes_pending = nw.read(nbytes=bytes_pending, generation=generation)
bytes_received += n
nw.tls_wants_write = False
except ssl.SSLWantReadError:
return
except ssl.SSLWantWriteError:
# TLS needs to write handshake/key-update data before we can continue reading
nw.tls_wants_write = True
self.modify_socket(nw, selectors.EVENT_READ | selectors.EVENT_WRITE)
return
except (ConnectionError, ConnectionAbortedError):
# The ConnectionAbortedError is also thrown by sabctools in case of fatal SSL-layer problems
self.reset_nw(nw, "Server closed connection", wait=False)
@@ -768,6 +810,10 @@ class Downloader(Thread):
if not bytes_pending:
break
# Ignore metrics for reset connections
if nw.generation != generation:
return
server = nw.server
with DOWNLOADER_LOCK:
@@ -780,33 +826,38 @@ class Downloader(Thread):
and sabnzbd.BPSMeter.bps + sabnzbd.BPSMeter.sum_cached_amount > self.bandwidth_limit
):
sabnzbd.BPSMeter.update()
while sabnzbd.BPSMeter.bps > self.bandwidth_limit:
while self.bandwidth_limit and sabnzbd.BPSMeter.bps > self.bandwidth_limit:
time.sleep(0.01)
sabnzbd.BPSMeter.update()
def check_assembler_levels(self):
"""Check the Assembler queue to see if we need to delay, depending on queue size"""
if (assembler_level := sabnzbd.Assembler.queue_level()) > SOFT_ASSEMBLER_QUEUE_LIMIT:
time.sleep(min((assembler_level - SOFT_ASSEMBLER_QUEUE_LIMIT) / 4, 0.15))
sabnzbd.BPSMeter.delayed_assembler += 1
logged_counter = 0
if not sabnzbd.Assembler.is_busy() or (delay := sabnzbd.Assembler.delay()) <= 0:
return
time.sleep(delay)
sabnzbd.BPSMeter.delayed_assembler += 1
start_time = time.monotonic()
deadline = start_time + 5
next_log = start_time + 1.0
logged_counter = 0
while not self.shutdown and sabnzbd.Assembler.queue_level() >= 1:
# Only log/update once every second, to not waste any CPU-cycles
if not logged_counter % 10:
# Make sure the BPS-meter is updated
sabnzbd.BPSMeter.update()
# Update who is delaying us
logging.debug(
"Delayed - %d seconds - Assembler queue: %d",
logged_counter / 10,
sabnzbd.Assembler.queue.qsize(),
)
# Wait and update the queue sizes
time.sleep(0.1)
while not self.shutdown and sabnzbd.Assembler.is_busy() and time.monotonic() < deadline:
if (delay := sabnzbd.Assembler.delay()) <= 0:
break
# Sleep for the current delay (but cap to remaining time)
sleep_time = max(0.001, min(delay, deadline - time.monotonic()))
time.sleep(sleep_time)
# Make sure the BPS-meter is updated
sabnzbd.BPSMeter.update()
# Only log/update once every second
if time.monotonic() >= next_log:
logged_counter += 1
logging.debug(
"Delayed - %d seconds - Assembler queue: %s",
logged_counter,
to_units(sabnzbd.Assembler.total_ready_bytes()),
)
next_log += 1.0
@synchronized(DOWNLOADER_LOCK)
def finish_connect_nw(self, nw: NewsWrapper, response: sabctools.NNTPResponse) -> bool:
@@ -900,7 +951,7 @@ class Downloader(Thread):
wait: bool = True,
count_article_try: bool = True,
retry_article: bool = True,
article: Optional["sabnzbd.nzbstuff.Article"] = None,
article: Optional["sabnzbd.nzb.Article"] = None,
):
# Some warnings are errors, and not added as server.warning
if warn and reset_msg:
@@ -909,13 +960,6 @@ class Downloader(Thread):
elif reset_msg:
logging.debug("Thread %s@%s: %s", nw.thrdnum, nw.server.host, reset_msg)
# Make sure this NewsWrapper is in the idle threads
nw.server.busy_threads.discard(nw)
nw.server.idle_threads.add(nw)
# Make sure it is not in the readable sockets
self.remove_socket(nw)
# Discard the article request which failed
nw.discard(article, count_article_try=count_article_try, retry_article=retry_article)

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 -OO
# Copyright 2007-2025 by The SABnzbd-Team (sabnzbd.org)
# Copyright 2007-2026 by 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
@@ -255,8 +255,7 @@ def diskfull_mail():
"""Send email about disk full, no templates"""
if cfg.email_full():
return send_email(
T(
"""To: %s
T("""To: %s
From: %s
Date: %s
Subject: SABnzbd reports Disk Full
@@ -266,9 +265,7 @@ Hi,
SABnzbd has stopped downloading, because the disk is almost full.
Please make room and resume SABnzbd manually.
"""
)
% (cfg.email_to.get_string(), cfg.email_from(), get_email_date()),
""") % (cfg.email_to.get_string(), cfg.email_from(), get_email_date()),
cfg.email_to(),
)
else:

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