Compare commits

...
157 Commits
Author SHA1 Message Date
Safihre 675d7714ca Skip symlink tests if creation is not possible
On Windows, creating symbolic links requires either an elevated shell or Developer Mode. This introduces a runtime check to verify if symlinks can be created. Tests that rely on symlink creation are now skipped if this check fails, preventing unnecessary test failures in environments without the required permissions.
2026-09-08 14:56:29 +02:00
Safihre bcd1585ea1 Set timeout for translations job
Prevents the workflow from running indefinitely.
2026-09-08 13:24:58 +02:00
Safihre 9d365facaa Import same_directory for path validation 2026-09-08 12:17:17 +02:00
Safihre 948500799a Skip filesystem link behavior tests on Windows
These tests rely on a specific behavior of '..' in paths involving symbolic links, which differs on Windows where '..' is collapsed before the filesystem resolves links.
2026-09-08 12:16:47 +02:00
mnightingale d8815ef983 Treat a dangling link as a taken name and refuse it as a write target 2026-09-08 11:19:38 +02:00
mnightingale ff537363c6 Sanitize each part before checking it for traversal or the admin folder 2026-09-08 11:19:37 +02:00
mnightingale b58a25df07 Pin the tarfile behaviour that contains members against links in the destination 2026-09-08 11:19:36 +02:00
mnightingale 1ce8faafeb Contain renames using the resolved paths so links cannot redirect them 2026-09-08 11:19:35 +02:00
mnightingale 7dbecb0a2d Skip links and other non-regular members when extracting tar files 2026-09-08 11:19:34 +02:00
Safihre 8343f182aa Pass Discord webhook secrets to release workflow 2026-09-08 11:14:07 +02:00
renovate[bot] d3f691e695 Update all dependencies (#3617)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-07 04:49:02 +00:00
Safihre d25d857fc4 Remove ISSUES.txt and refer to wiki for known issues 2026-09-04 11:47:44 +02:00
Safihre 64f342ca1d Use dedicated token for tools update workflow
Replaces `github.token` with `secrets.AUTOMATION_GITHUB_TOKEN` to provide consistent and appropriate permissions for automated tasks like creating pull requests.
2026-09-04 11:43:30 +02:00
Safihre ab3ba4a53a Add Discord integration for release notes
Posts release notes automatically to designated Discord webhooks, supporting separate channels for pre-release and stable builds.
2026-09-04 11:37:54 +02:00
github-actions[bot]andSABnzbd Automation 169a42b08c 7-Zip 26.03 (#3615)
Co-authored-by: SABnzbd Automation <bugs@sabnzbd.org>
2026-09-04 11:35:45 +02:00
Safihre 6cbe811d10 Restore checkboxes color 2026-09-04 09:03:26 +02:00
SABnzbd Automation 33ff6800d2 Update translatable texts
[skip ci]
2026-09-04 06:50:18 +00:00
mnightingale ec61683097 Downloader hot path improvements (#3604)
* Guard the speed counters with their own lock so updates are not lost

* Update the speed counters without taking the Downloader lock

* Skip the downloader sleep once the loop rather than the connection is the limit

* Remove unused variable
2026-09-04 08:49:35 +02:00
SABnzbd Automation 069f978e64 Update translatable texts
[skip ci]
2026-09-03 09:25:36 +00:00
Safihre c65ce5d5aa Add tooltip to explain search filters in queue and history
Provide users with guidance on advanced search capabilities, including filter options like `cat:`, `status:`, and `priority:`.
Closes #3558
2026-09-03 11:24:44 +02:00
mnightingale 443b34ce55 Check the speed limit on its own lock so a held back connection does not hold up the Downloader 2026-09-02 22:13:55 +02:00
mnightingale fbe07dfb7e Refresh the time after waiting so the statistics keep their interval 2026-09-02 22:11:44 +02:00
mnightingale 168622ea47 Remove the unused MultiAddQueue and use a plain queue 2026-09-02 22:10:34 +02:00
Safihre ab702860df Refactor color scheme implementation
Moves theme-specific styles into main CSS files for each interface,
leveraging `color-scheme` and `light-dark()` CSS functions. This
consolidates styling, reduces HTTP requests, and improves automatic
dark/light mode detection based on OS preferences.
2026-09-02 22:02:33 +02:00
mnightingale 4a999a1908 Fix macOS tray crashing when the notification center is unavailable 2026-09-01 20:05:34 +02:00
mnightingale 975c552a6a Safer open folder from macOS menu 2026-09-01 18:47:03 +02:00
mnightingale 20915cc626 Fix mobile dropdown menu styling 2026-08-31 17:44:22 +02:00
mnightingale 4fde6e490c Update jQuery UI to 1.14.2 2026-08-31 16:32:13 +02:00
mnightingale 58c3c13954 Update jQuery to 3.7.1 2026-08-31 16:32:13 +02:00
mnightingale 7b3d1d41ab Load one copy of jQuery, jQuery UI and Bootstrap instead of two 2026-08-31 16:32:13 +02:00
mnightingale cb1102d992 Match navbar heights between styles 2026-08-31 14:31:01 +02:00
mnightingale ecf5e27c04 Let the browser hold static files for good 2026-08-31 08:58:41 +02:00
mnightingale cd96dadcc3 Send the restart request below the configured URL base 2026-08-31 08:58:41 +02:00
mnightingale fb2660dbb9 Serve Glitter's scripts as files the browser can cache 2026-08-31 08:58:41 +02:00
renovate[bot] f9cb5b302b Update all dependencies 2026-08-31 08:56:46 +02:00
SABnzbd Automation 614b3faca6 Update translatable texts
[skip ci]
2026-08-30 18:59:36 +00:00
mnightingale e4162b093a Store the API connection info per config file so instances do not collide 2026-08-30 20:59:01 +02:00
mnightingale e1009e1e92 Install the browser and its system dependencies in one step 2026-08-30 17:01:15 +02:00
mnightingale f8781e1e35 Only resolve the hostname when the access list actually uses it 2026-08-30 17:01:15 +02:00
mnightingale be5d394ebd Tolerate the reload that deleting a server triggers 2026-08-30 17:01:15 +02:00
mnightingale 55285c5cf9 Skip the save button's artificial one second delay with Playwright's clock 2026-08-30 17:01:15 +02:00
mnightingale c3f6b2d582 Keep pytest-playwright out of the pytest session tavern nests inside a test 2026-08-30 17:01:15 +02:00
mnightingale 5088e14fa6 Drive the functional tests with Playwright instead of Selenium 2026-08-30 17:01:15 +02:00
mnightingale 139b4a52b6 Run test coroutines on a thread of their own when a loop is already running 2026-08-30 17:01:15 +02:00
mnightingale 7a852e8654 Pin h11, which uvicorn requires and selenium was supplying by accident 2026-08-30 17:01:15 +02:00
mnightingale fd9acd2ea8 Serve the urlgrabber tests from a local server instead of httpbin 2026-08-30 17:01:15 +02:00
SABnzbd Automation eb673d3956 Update translatable texts
[skip ci]
2026-08-30 08:11:49 +00:00
mnightingale f7513c05b9 Stop the nested tavern session collecting the xdist worker cache dirs (#3599) 2026-08-30 10:11:14 +02:00
Safihre e3bc15e8e6 Make Compact Great Again 2026-08-28 14:48:13 +02:00
Safihre b263c6cfe6 Replace anonymous session cookie with stable CSRF identity (#3596)
Previously, UI access for login-bypassed clients relied on issuing a stateless "anonymous session" cookie to enable CSRF protection. This commit removes that cookie mechanism.

Instead, when the login is bypassed (e.g., for local clients without credentials), the CSRF token is now bound to a stable, internal "anonymous" identity. This maintains robust CSRF protection for browser interactions without requiring an explicit session cookie, simplifying overall session management.
2026-08-28 11:19:54 +02:00
mnightingale d990a17424 Enable direct_decode by default, paced against what the disk can do (#3586)
* Watch whether the download directory keeps up with writes placed where they belong

* Default direct_decode on, refusing a sink while the destination is not keeping up

* Measure what the destination drains and report it as a rate

* Pace the downloader against the measured write rate rather than the cache level

* Handle SparseUnsupported and do not disable direct_write just because it's unsupported for a file

* Let sabctools carve the write totals into intervals instead of tracking them here

* sabctools 9.7.1
2026-08-27 16:19:43 +02:00
SABnzbd Automation 38c2a7bca7 Update translatable texts
[skip ci]
2026-08-27 12:40:32 +00:00
Safihre e2a4d9953b Improve NNTP error reporting with raw server messages
Instead of interpreting and translating common NNTP error messages (e.g., authentication failure, too many connections) into generic localized strings, this change passes the raw server response directly to the user. This provides more accurate and specific diagnostic information for troubleshooting server-related issues.
Closes #3563
2026-08-27 14:39:41 +02:00
Safihre 5696a667e7 Show in-progress status for server tests
Add an `alert-info` class to the result box while a server test is running,
providing visual feedback to the user that the process is ongoing.
2026-08-27 14:25:06 +02:00
SABnzbd Automation 0651dd7a3a Update translatable texts
[skip ci]
2026-08-27 11:05:45 +00:00
mnightingale b192a7eca4 Persistent sessions, CSRF tokens, and no apikey in the web interface (#3559)
* Add a session store that keeps web-UI logins in the admin folder

* Authenticate the web interface with session cookies and CSRF tokens

* Stop embedding the apikey in the web interface

* Cover the session, CSRF and apikey changes
2026-08-27 13:05:12 +02:00
SABnzbd Automation 75f7db398a Update translatable texts
[skip ci]
2026-08-27 09:55:59 +00:00
Safihre 90f092a1a5 Automate LinuxServer.io Docker image builds
Trigger the corresponding LinuxServer.io Docker image build (develop for
pre-releases, master for stable) after a SABnzbd release, ensuring the
Docker images are kept up-to-date.
2026-08-27 11:54:55 +02:00
mnightingale f498147189 Restrict mode-based API key logic to actual API routes
The `mode` parameter in API calls enables specific behaviors and key bypasses (e.g., 'version', 'auth', NZB-key). Previously, this logic was applied universally by `check_apikey`. This change ensures such `mode`-based logic is only honored when accessing the dedicated `/api` endpoint, preventing potential API key bypasses on other web UI routes.
2026-08-25 13:24:22 +02:00
mnightingale e36d989ee5 Sanitize PP-values 2026-08-25 13:24:13 +02:00
Safihre e0acbd75e2 Harden paths that could overwrite __ADMIN__ files
Prevent directory creation in `renamer` to overwrite `__ADMIN__`
Check the whole new path for `__ADMIN__` in `renamer`
Drop `__ADMIN__` from names that are allowed to have sub-directories
Resolve the path before checking it against `__ADMIN__`
2026-08-25 13:22:12 +02:00
Safihre 2ce13bdd9a Prevent directory traversal in Deobfuscate 2026-08-25 13:21:57 +02:00
Safihre 93546e5b7a Add SafeUnpickler to guard against pickle-attacks (#3585)
* Add SafeUnpickler to guard against pickle-attacks

* Harden pickle unpickler with explicit allowlist

The previous `SafeUnpickler` allowed any class from `sabnzbd.*` by wildcard, which could still enable deserialization attacks if a "gadget class" (e.g., with a malicious `__del__` method) was present within our own package.

This commit renames the class to `RestrictedUnpickler` and changes its logic to only allow classes explicitly defined in `_SAFE_GLOBALS`. This significantly enhances security by preventing the unpickling of any unlisted classes, including those from within `sabnzbd`. Adds `os.stat_result` and `sabnzbd.nzb.*` classes to the allowlist for compatibility.
2026-08-24 22:40:04 +02:00
mnightingale 5973e5b6ed Stop tests that create NZBs from racing (#3590) 2026-08-24 09:00:03 +02:00
SABnzbd Automation 0fe92487b6 Update translatable texts
[skip ci]
2026-08-24 05:38:32 +00:00
renovate[bot] 743ff89cff Update all dependencies (#3591)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-24 07:37:39 +02:00
SABnzbd Automation 43f22b579f Update translatable texts
[skip ci]
2026-08-21 12:48:13 +00:00
Safihre 817ea452ba Correct wording for Quota period size 2026-08-21 14:47:33 +02:00
SABnzbd Automation 8c21f47f4c Update translatable texts
[skip ci]
2026-08-21 09:08:57 +00:00
mnightingale 3813a810ed Write articles through sabctools.FileWriter, and optionally straight from the decoder (#3562)
* Use sabctools.FileWriter for article writes

* Keep the FileWriter open on the NzbFile, bounded by an LRU

* Stream decoded articles straight to their file

* Fail the article, not the connection, when a streaming write fails

* Pause on a disk error from a streamed write

A full disk cannot be fixed by fetching the article again, so mirror the assembler
and pause instead of spending its retries and failing the job as incomplete.

* Treat an exhausted quota as a full disk

* Use sabctools 9.7.0
2026-08-21 11:08:24 +02:00
github-actions[bot]andSABnzbd Automation 602464349f par2cmdline-turbo 1.5.0 (#3584)
Co-authored-by: SABnzbd Automation <bugs@sabnzbd.org>
2026-08-20 18:27:18 +02:00
Safihre bdd821233f Re-enable par2cmdline in tools-update workflow 2026-08-20 17:30:33 +02:00
mnightingale 611dfa74d2 Fix applying changes to RSS filters (#3582) 2026-08-20 09:55:26 +02:00
coopa11yandcoopa11y 21d639bf5f Announce news server test results to screen readers (#3566)
Co-authored-by: coopa11y <coopa11y@users.noreply.github.com>
2026-08-19 11:31:14 +02:00
coopa11yandcoopa11y 6d897a5f23 Announce notification test results to screen readers (#3567)
Co-authored-by: coopa11y <coopa11y@users.noreply.github.com>
2026-08-19 11:31:06 +02:00
mnightingale 537ac2e7a4 Tighten IPv6 and Host header handling (#3564)
* Refuse unbracketed IPv6 addresses in the Host header

* Bracket the IPv6 client address logged with warnings

* Decide the Secure cookie attribute from the request scope
2026-08-19 11:30:13 +02:00
mnightingale cb2c44cfc2 Unpack rar sets that par2 moved into a subfolder (#3553)
* Reproduce bug

* Let sanitize_filename keep par2 sub-directories

Par2 sets can store their files inside a folder, always using a forward slash as
separator no matter which platform created the set. We replaced that slash with an
underscore, so the name could never match what par2 called the file.

With allow_subdirs the separator is kept and every part is sanitized on its own.
The result stays local to the folder it is used in: empty parts, "." and ".." are
dropped, so neither a leading slash nor any amount of traversal can point outside.

* Write files into the sub-directory par2 names them in

The name from the par2 pack is what we already rename files to, but the separator
was stripped so the file landed flat with an underscore. Post-processing then had
to move it into place afterwards, which is how the volumes ended up somewhere the
unpacker did not look.

Assemble straight into the sub-directory instead. get_unique_filepath() creates the
folder and returns the name relative to the download folder, so nzf.filename now
holds that relative name. analyze_rar_filename() takes the basename, so a setname
still matches what rar_unpack() derives from a path with setname_from_path().

* Match existing files in sub-directories on retry

check_existing_files() listed the job folder without descending into it, so on a
retry the volumes par2 put in a folder of their own were never matched and got
downloaded again.

List the sub-directories too, skipping the admin folder, and match on the name
relative to the job folder. Rename bookkeeping is normalized to the platform
separator, par2 always reports a forward slash.

* Find rar sets in the job's sub-directories

* Wait for the direct unpacker to finish

* Update nzf.setname and nzf.vol after deobfuscating names

* Fix double extraction

* Ruff
2026-08-19 11:13:39 +02:00
mnightingale adde7b961c Fix rss "Clear Downloaded" did not appear to do anything (#3569) 2026-08-18 12:30:38 +02:00
mnightingale 9639d651f4 Don't let uvicorn logging pollute the log and notifications (#3579) 2026-08-18 12:26:26 +02:00
mnightingale f481496e5d Fix rss clearing at startup and downloaded items still in the feed (#3576)
* Only purge unconfigured rss feeds at startup

* Only perform remove obsolete actions if the feed was read

* Update seen_at so downloaded items are not removed while still in the feed

* Increase hardcoded retention to 7 days
2026-08-18 11:46:51 +02:00
renovate[bot]andSafihre e0bf9218bb Update all dependencies (#3575)
* Update all dependencies

* Add feedparser-sgmllib

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Safihre <safihre@sabnzbd.org>
2026-08-18 10:01:04 +02:00
Safihre 19b597d21b Add static cache busting for Config Auto colorscheme 2026-08-18 08:50:08 +02:00
mnightingale 86a2025eca Use root relative URLs (#3572) 2026-08-17 21:57:20 +02:00
SABnzbd Automation 0996998ed9 Update translatable texts
[skip ci]
2026-08-17 18:58:34 +00:00
mnightingale 583617f0a9 Fix submission of server forms when priority, displayname, or notes changes (#3578) 2026-08-17 20:57:42 +02:00
mnightingale d45a1d8bf0 Fix pytest-xdist failure due to selenium driver in class global (#3573)
* Fix pytest-xdist failure due to selenium driver in class global

* ruff
2026-08-16 22:41:03 +02:00
SABnzbd Automation 2e99fd6fd0 Update translatable texts
[skip ci]
2026-08-16 13:47:18 +00:00
mnightingale cf26260910 Fix display of downloaded rss history (#3570) 2026-08-16 15:46:28 +02:00
mnightingale 59218a687d Fix race in TestAddingNZBsClean and share the NZB-adding helpers (#3571)
Jobs are listed in the history output as soon as they enter the
post-processing queue, and a stopped job has its status set to Failed at
the very start of process_job. The duplicate alternative is only released
near the end of it, so waiting for the job to show up in the history as
failed does not guarantee the alternative was already released. The gap
is tiny when running serially, but wide enough to fail the test under the
load of pytest-xdist. Wait for the label to be dropped instead.

Also move the helpers shared by both adding-NZB test classes into a base
class in testhelper, so the clean tests no longer have to import the
other test module to copy its methods.
2026-08-16 15:46:05 +02:00
Safihre 61df709a04 Add static cache busting for Auto colorscheme
Yes ugly, but it works for major updates
2026-08-12 10:55:18 +02:00
Safihre 1fcada54f9 Fetch full history for Claude AI review workflow
The Claude AI code action requires the complete Git history to properly diff pull requests against their base branches.
2026-08-11 13:31:29 +01:00
SABnzbd Automation 289b91a3de Update translatable texts
[skip ci]
2026-08-11 12:29:08 +00:00
mnightingale 35d5355f49 Replace CherryPy with Uvicorn and Starlette (#3550)
* Migrate web interface from CherryPy to Uvicorn/Starlette

Squashed rebase of feature/uvicorn (34 commits) onto develop, reconciled
with ~3 months of intervening develop changes.

Replaces the CherryPy webserver and request handling with Uvicorn/Starlette
across the API, web interface, RSS, config pages and related modules.

Reconciliation with develop during the rebase:
- api.py: kept develop's security/behaviour fixes (orphan path-traversal
  guard, expanded log redaction incl. host_whitelist and
  remote_label_replacement, get_dconfig single-return, get_retryable_jobs,
  connections default, translated NNTP test errors) on top of the Starlette
  request/response rewrite.
- interface.py: ported the RSS route handlers to develop's DB-backed
  RSSRepository API (process_feed, rss_repository / find_job_by_url /
  clear_feed / clear_downloaded / flag_downloaded).
- misc.py: kept develop's hachoir-based get_media_duration.
- requirements.txt: dropped the CherryPy stack, adopted develop's newer pins.

Also applied ruff --fix (PEP 604 unions, builtin generics) to align with
develop's lint config.

Verified: ruff check, black --check, and the affected test suites
(9413 passed, 1 skipped) all pass.

* Update starlette/uvicorn versions

* Fix race issues in global rss state

* Fix test race in server shutdown

The uvicorn migration turned /shutdown (and the shutdown API) into fire-and-forget: it spawned shutdown_program() in a background thread and replied immediately, whereas develop ran it synchronously and only replied once halt() had persisted all state. Because the module-scoped test teardown doesn't wait for the process to exit, the next module's clean_cache_dir wiped the shared cache dir (and reused the fixed port) while the previous instance was still saving state and holding the port — producing the three intermittent failures (deleted sabnzbd.log → "File log disabled or not found"; un-persisted [sorters] → KeyError; stale instance → missing wizard .quoteBlock).

* Fix robots and description, add favicon

* Remove remains of http basic auth

* Setup Starlette once configuration is available, fix static file relative cwd and url_base config

* abort_and_show_error when webserver fails to start

* Guard stopping webserver that never started

* Delegate XFF handling to ProxyHeadersMiddleware

* Merged params at request.state.params instead of modifying private apis

* Both shutdown routes share implementation and do not block event loop

* Run sync handlers via run_in_threadpool and facilitate eventual migration to async

* Pool database connections

* Online backup of database due to WAL changes

* Fix exception on None request.client (test clients or unix sockets)

* Fix flakey tests due to process not fully shutting down

* Restore X-Frame-Options behaviour via middleware

* Fix set_config_default with multiple keywords

* Remove broken logging call

* Restore api logging functionality

* Cache-Control: no-store

* Login only via POST

* Remove 401 (basic-auth) and add 404 handling via redirect

* Fix crash when shutdown not an int

* Use BaseRedirectResponse helper

* Remove trailing slashes from wizard routes

* URL helper, absolute URLs everywhere, fixes issues with nested navigation

* Fix scheduler adding multiple daysofweek

* Restore CherryPy api behaviour merging body with query params (body wins)

* Clearer documentation of get_request_params and request_params

* First stage supporting gradual api async

* Fix rss ajax consuming flash

* Restore access log functionality

* Hostname check in middleware

* Request logging in middleware

* Param parsing in middleware

* Security checks in middleware

* secured_expose is now purely route registration

* Lookup api handler once per request

* Fix flakey alert dialogs

* Trigger restart via BackgroundTask

* Restore CherryPy first param wins and get/post consistency

* Remove dead code

* Secure cookies based on protocol the client used

* Fix various issues with port_is_free

1. port_is_free answered the wrong question. It connect-probed ("is something answering?") rather than bind-probed ("can I bind?"). A port could report free and then kill startup at uvicorn's bind().
2. The bind-all remap crossed address families. :: was mapped to 127.0.0.1, probing IPv4 for an IPv6 bind — a regression against portend, which maps :: → ::1.
3. The call sites passed the wrong host. browserhost is a client-reachable address; the thing that has to be bindable is web_host.
4. Errors were swallowed. A bare except OSError hid gaierror, so an unresolvable host reported "free".
5. find_free_port had a port-0 trap. Under a bind-probe, currentport=0 always succeeds and returned 0 — the old failure sentinel. Now guarded, and None instead of 0.
6. Ports 80/443 were misdiagnosed. EACCES was folded into "occupied", producing ten futile probes and a panic claiming another program held the port. PermissionError now propagates to a dedicated panic explaining the actual remedies.
7. The tests were largely tautological. Three tests covering one branch, an IPv6 test with no IPv6 in it, a timeout test that never engaged the timeout, TOCTOU-prone fixed-range probes, no SO_REUSEADDR on the helper listener, and nothing asserting the property that matters — that "free" implies bindable.
8. A portability bug I introduced, then fixed. I'd baked Linux SO_REUSEADDR overlap semantics into four assertions; macOS differs. Now platform-aware, with the IPv6 regression re-covered by checking the socket family directly.

* Claim the bind address for uvicorn on startup, resolves "49" in err handling from cherrypy

* Rename function BaseRedirectResponse to base_redirect_response

* Restore error response on change web directory

* Add missing typings

* Fix return type of retry job for future types

* A better fix for xdist compatibility - test overwrote db_path

* Secure session cookies (rss flash)

* Inline or remove some functions

* Retry job futuretype behaviour

* Sneak a worksteal fix in

* Test and fix retry_job futuretype behaviour
2026-08-11 13:27:51 +01:00
mnightingale ec6ba3baae Speed up tests with pytest-xdist (#3546)
* Speed up tests with pytest-xdist

* Ignore request failures when the server disappeared

* Fix tests which modify module globals

* Fix lang change leaking

* Fix transaction compilation order breaking tests

* Always load a clean config and fix related tests

* No module globals

* Fix other test classes assigning module level by making calls

* Replace from sabnzbd.cfg import so monkeypatch works

* More global poisoning

* Fix dependant tests which worksteal breaks

* More global vars

* Drop loadscope until more failures are resolved

* Due to how pytest-xdist is implemented, the -s/--capture=no option does not work

* monkeypatch db_path

* Also patch startup_done

* loadscope
2026-08-10 17:44:18 +01:00
Safihre d6474cb695 Skip par2cmdline update for now due to custom macOS binaries 2026-08-10 14:11:30 +01:00
Safihre 4520de77ad Correct ssdp.py for black formatting 2026-08-10 12:44:20 +01:00
Safihre ada9d83593 Refine file extension utilities for efficiency and robustness
Adopt `frozenset` for extension collections to enable faster lookups and ensure immutability. Add explicit `utf-8` encoding to file reads to prevent locale-dependent issues when identifying text/NZB files. Optimize by caching results of `all_possible_extensions` to avoid redundant computations.
2026-08-10 12:36:16 +01:00
Safihre 58386e0b61 Refine local self-signed certificate generation
Adds `BasicConstraints` to the generated certificates for better compliance and explicitly marks them as non-CA. Changes the `SubjectAlternativeName` extension to non-critical, improving client compatibility. Improves robustness in SAN list generation and adds type hints for clarity.
2026-08-10 12:30:42 +01:00
SABnzbd Automation 4601f4b690 Update translatable texts
[skip ci]
2026-08-10 11:25:53 +00:00
coopa11yandcoopa11y fd191d1b79 Add screen reader names to Glitter and Config dialogs (#3545)
Co-authored-by: coopa11y <coopa11y@users.noreply.github.com>
2026-08-10 12:25:17 +01:00
Safihre 5014673f87 Improve SSDP XML generation and refine module implementation
Escapes dynamic data in the SSDP device description XML to prevent issues with special characters and improve robustness. Enhances code clarity and maintainability through explicit constructor parameters, type hints, and updated docstrings. Also adds debug logging for SSDP broadcast failures and renames the module-level singleton for better Python convention.
2026-08-10 12:24:30 +01:00
SABnzbd Automation 14ce150b31 Update translatable texts
[skip ci]
2026-08-10 10:50:18 +00:00
coopa11yandcoopa11y 8e39722359 Improve Glitter queue and history table accessibility (#3539)
Co-authored-by: coopa11y <coopa11y@users.noreply.github.com>
2026-08-10 12:49:33 +02:00
Safihre ba36e62695 Refactor Config object (#3552) 2026-08-10 09:24:53 +02:00
SABnzbd Automation 250a4dbf2a Update translatable texts
[skip ci]
2026-08-10 07:24:37 +00:00
Safihre 3867cefa0a Update version to 5.2.0-dev 2026-08-10 09:23:52 +02:00
Safihre d530764a6d Allow collaborators to trigger Claude review 2026-08-10 08:59:37 +02:00
renovate[bot] b5a7385d48 Update all dependencies (#3557)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-10 06:10:25 +00:00
Safihre 40860c68ca Correct Notifications page display 2026-08-08 21:34:48 +02:00
mnightingale 3213cd74cf Rebuild macOS par2 binary (#3554) 2026-08-08 11:52:17 +02:00
Safihre b8838c4728 Improvements to Notification options display 2026-08-07 11:03:39 +02:00
Safihre 047ed77dd4 Remove stray MULTIPAR_COMMAND 2026-08-07 10:11:51 +02:00
Safihre 78cb553b14 Fix config UI selection and update direct unpack log message
Correctly pre-select the 'all' option for `history_retention_option` in the config UI by using the correct variable.
2026-08-06 16:15:09 +02:00
jcfp c5ebea7bbd use XDG_CURRENT_DESKTOP as an alternative GUI indicator (#3551) 2026-08-06 11:42:51 +02:00
Safihre 7b02c74386 Add missing guard_restart to https_chain 2026-08-06 10:43:21 +02:00
SABnzbd Automation 0c3464e6a2 Update translatable texts
[skip ci]
2026-08-05 17:15:11 +00:00
Ben Hamilton (Ben Gertzfield) d889d4fd30 Don't log warning during clean shutdown (#3548) (#3549)
`SIGTERM` is an expected part of a clean shutdown.

Previously, the signal handler posted a log warning for any signal received.

This PR turns down the log level to info for `SIGTERM` (non-Windows only).

Tested:

% python3 -m venv venv
% source venv/bin/activate
% pip install -r dependencies.txt
% python3 -OO SABnzbd.py

In another terminal, ran `kill -TERM $PID`.

Confirmed in logs that log level was now set to `INFO`:

```
2026-08-05 08:37:10,296::INFO::[__init__:217] Signal 15 caught, saving and exiting...
```

Full logs:

https://gist.github.com/bhamiltoncx/2f8845b63c52e47fc4f00de263c21152
2026-08-05 19:12:55 +02:00
Safihre 70f89e98e8 Update text files for 5.1.0RC2 2026-08-03 15:54:12 +02:00
Safihre 2cb12a07c9 Update 'Mark as Completed' link to a button 2026-08-03 14:53:42 +02:00
mnightingale 3d7f5d4289 Relax disk space requirements when not unpacking and on the same device (#3535)
* Test existing behaviour

* Relax disk space requirements when not unpacking and the same device
2026-08-03 11:44:11 +02:00
Safihre 3abf4c7bdb Update sabctools to 9.6.3 2026-08-03 11:07:34 +02:00
mnightingale 947b2b815c Fix assembler ready bytes accounting (#3538) 2026-08-03 09:01:29 +02:00
thezoggy d167fb0fe7 fix active pagination for light theme (#3541) 2026-08-03 08:52:22 +02:00
renovate[bot] b7da5b6684 Update actions/setup-python action to v7 (#3543)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-03 08:42:06 +02:00
Andre Popovitch df9c57f539 Prevent shutdown deadlock when a second signal arrives during halt (#3537) 2026-08-03 08:40:32 +02:00
renovate[bot] d5a7f8631c Update dependency jaraco.functools to v4.6.0 (#3542)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-03 08:29:34 +02:00
mnightingale dcb618ce99 Improve wait for direct unpacker to finish (#3540) 2026-08-02 21:16:07 +02:00
mnightingale dc5620a52c cgroup-aware memory limits for the article cache (#3528)
* Apply memory limits from cgroups

* Apply cgroup limits to article cache

* Fix this bug

* _physical_memory return None when undetermined

* Mark platform on test group

* Remove MemoryInfo dataclass

* Cap memory with reservation

* Keep the slightly broken 32 vs 64 bit code

* 512 *MEBI because the numbers look nicer
2026-07-31 09:42:47 +03:00
mnightingale 40a3941b9e Fix os.umask race and unnecessary (#3530) 2026-07-30 11:24:06 +03:00
mnightingale eb9229d326 Prevent concurrent dirscanner scans (#3529) 2026-07-29 22:51:41 +03:00
coopa11yandcoopa11y 0411e8acc1 Label schedule time, enable, and delete controls for screen readers (#3525)
* Label schedule time, enable, and delete controls

* Use ARIA label for schedule enable control

---------

Co-authored-by: coopa11y <coopa11y@users.noreply.github.com>
2026-07-28 21:12:47 +03:00
mnightingale f405b8927a Reduce BPS allocations and fix scale (#3527)
* Replace per-second bps list copy

* Consistent x-axis scale after startup

* Advance time when padding
2026-07-28 19:50:14 +03:00
mnightingale 47a507f5a6 Fix flaky test_api_queue_sort test and to_unit at boundaries (#3522)
* Fix flaky sort test by comparing at the same resolution

* Fix consistency of values printed at reduced precision

* Replace the float-string roundtrip with rounding and adjust to next unit if required

* Comment styling
2026-07-28 17:59:47 +03:00
Amajiro bdca9715b2 Add Ayatana AppIndicator tray support on GNOME (#3508)
* Add Ayatana AppIndicator tray support on GNOME

* Only load tray icon fallback backends when needed
2026-07-28 17:44:00 +03:00
SABnzbd Automation 0954ac143d Update translatable texts
[skip ci]
2026-07-28 14:43:46 +00:00
coopa11yandcoopa11y 9122633907 Label SABnzbd login fields and help link for screen readers (#3524)
* Label SABnzbd login fields and help link

* Use ARIA labels for login fields

---------

Co-authored-by: coopa11y <coopa11y@users.noreply.github.com>
2026-07-28 17:42:48 +03:00
renovate[bot] 1b6aea3afb Update all dependencies (#3526)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-27 08:43:03 +03:00
coopa11yandcoopa11y af10190e0b Improve Glitter status table accessibility (#3523)
Co-authored-by: coopa11y <coopa11y@users.noreply.github.com>
2026-07-26 20:07:31 +03:00
SABnzbd Automation 1acfc5139c Update translatable texts
[skip ci]
2026-07-26 13:28:53 +00:00
Parsa YazdaniandQuixThe2nd 404060373b feat: add 'Sort by Remaining Size' queue sort option (#3512)
* feat: add 'Sort by Remaining Size' queue sort option

Add a new 'remaining_bytes' sort field that sorts the queue by absolute
remaining bytes (bytes - bytes_tried), complementing the existing
'remaining' sort which uses percentage downloaded and the 'size' sort
which uses total bytes.

Changes:
- nzbqueue.py: add remaining_bytes sort field, fix update_sort_order()
  to parse field+direction from config instead of hardcoding 'remaining'
- skintext.py: add Glitter-sortRemainingBytesAsc/Desc translation strings,
  update auto_sort explanation text
- Glitter UI: add dropdown entries and JS handlers for both directions
- Config: add auto_sort options for remaining_bytes asc/desc
- Tests: parametrize remaining_bytes asc/desc against sizeleft slot field

* style: wrap long string for Black formatting

* fix: limit remaining-size sorting to ascending

---------

Co-authored-by: QuixThe2nd <QuixThe2nd@users.noreply.github.com>
2026-07-26 16:28:08 +03:00
coopa11yandcoopa11y a84544bef8 Improve Glitter message accessibility (#3518)
Co-authored-by: coopa11y <coopa11y@users.noreply.github.com>
2026-07-25 12:50:52 +03:00
coopa11yandcoopa11y f38b602924 Improve interface options form accessibility (#3516)
Co-authored-by: coopa11y <coopa11y@users.noreply.github.com>
2026-07-25 11:50:58 +03:00
mnightingale db57321cb8 Fix postproc scripts on Windows (#3514)
* Verify external_processing failure on Windows

* Implement fix

* Clip complete_dir and newfiles in external_processing
2026-07-25 11:50:20 +03:00
mnightingale b825636d3f Fix crc32 may be being combined out-of-order (#3519) 2026-07-25 11:47:23 +03:00
SABnzbd Automation fa3f8735ea Update translatable texts
[skip ci]
2026-07-25 05:04:06 +00:00
mnightingale c359b21d89 Ruff styling for move None to the end of the type union (#3517) 2026-07-25 08:03:27 +03:00
coopa11yandcoopa11y 3ab1782dc2 Improve Add NZB form accessibility (#3511)
Co-authored-by: coopa11y <coopa11y@users.noreply.github.com>
2026-07-22 22:15:35 +03:00
Safihre 91c228353b Correct Signal Wakeup FD Registration for DirScanner
When `DirScanner` is initialized on the main thread, `asyncio.new_event_loop()` can register its self-pipe as the process-wide signal wakeup FD. As the `DirScanner`'s loop runs and is closed on a separate thread, this registration would become stale, potentially breaking signal delivery during application shutdown. Explicitly unregistering the FD prevents this issue.
2026-07-21 15:39:10 +02:00
coopa11yandcoopa11y 1336d66f78 Restore keyboard access to queue actions (#3503)
Co-authored-by: coopa11y <coopa11y@users.noreply.github.com>
2026-07-21 15:25:04 +02:00
coopa11yandcoopa11y 1f7bec651d Improve Glitter history row accessibility (#3504)
Co-authored-by: coopa11y <coopa11y@users.noreply.github.com>
2026-07-20 10:24:13 +02:00
SABnzbd Automation 8f02e59c31 Update translatable texts
[skip ci]
2026-07-20 08:24:01 +00:00
coopa11yandcoopa11y efb16cc69b Improve Glitter search and pagination accessibility (#3505)
* Improve Glitter search and pagination accessibility

* Fixed: Preserve pagination keyboard shortcuts

---------

Co-authored-by: coopa11y <coopa11y@users.noreply.github.com>
2026-07-20 10:23:24 +02:00
SABnzbd Automation f6020aa9f7 Update translatable texts
[skip ci]
2026-07-20 06:35:11 +00:00
renovate[bot] 2d2b88e771 Update all dependencies (#3509)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-20 08:34:32 +02:00
SABnzbd Automation 6731da2d68 Update translatable texts
[skip ci]
2026-07-17 10:23:59 +00:00
Safihre cf8ab5a8d5 Suggest NNTP pipelining increase for high-latency connections
During NNTP server tests, detect high latency and low pipelining settings.
Provide a helpful warning to users to consider increasing their 'Articles per request'
setting to improve download speed.

Closes #3284
2026-07-17 12:23:17 +02:00
Safihre 636aa91e21 Restore queue action buttons 2026-07-17 08:58:52 +02:00
217 changed files with 13287 additions and 6260 deletions

No files matched your search

+8 -5
View File
@@ -11,7 +11,7 @@ env:
PYTHONNODEBUGRANGES: 1
# For macOS we download the official Python, because the GitHub one only support newer macOS 11+ versions
# We also use the specific pin for Windows release, so Renovate can update it all at once
PYTHON_VERSION: "3.14.6"
PYTHON_VERSION: "3.14.7"
jobs:
build_windows:
@@ -31,7 +31,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Set up Python
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: ${{ matrix.architecture }}
@@ -123,7 +123,7 @@ jobs:
- uses: actions/checkout@v7
- name: Set up Python
# Only use this for the caching of pip packages!
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: "3.14"
cache: pip
@@ -144,7 +144,7 @@ jobs:
run: |
python3 --version
pip3 install --upgrade pip wheel
pip3 install -r requirements.txt --no-binary cffi,CT3,PyYAML --no-dependencies
pip3 install -r requirements.txt --no-binary cffi,CT3,PyYAML,httptools --no-dependencies
pip3 install -r builder/requirements.txt --no-dependencies
- name: Import macOS codesign certificates
# Taken from https://github.com/Apple-Actions/import-codesign-certs/pull/27 (comments)
@@ -191,7 +191,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Set up Python
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: "3.14"
cache: pip
@@ -214,6 +214,9 @@ jobs:
env:
AUTOMATION_GITHUB_TOKEN: ${{ secrets.AUTOMATION_GITHUB_TOKEN }}
REDDIT_TOKEN: ${{ secrets.REDDIT_TOKEN }}
LINUXSERVER_WEBHOOK_TOKEN: ${{ secrets.LINUXSERVER_WEBHOOK_TOKEN }}
DISCORD_WEBHOOK_TESTING: ${{ secrets.DISCORD_WEBHOOK_TESTING }}
DISCORD_WEBHOOK_STABLE: ${{ secrets.DISCORD_WEBHOOK_STABLE }}
run: |
pip3 install -r builder/release-requirements.txt --no-dependencies
python3 builder/release.py
+7 -1
View File
@@ -19,8 +19,14 @@ jobs:
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
# Full history so the review can diff the PR against its base branch
fetch-depth: 0
- uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
# Actual triggering is gated by the job-level `if` above; this disables
# the action's internal write-permission check, which contributors fail
allowed_non_write_users: "*"
+4 -2
View File
@@ -53,7 +53,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
cache: pip
@@ -67,5 +67,7 @@ jobs:
python -m pip install --upgrade pip wheel
pip install -r requirements.txt --no-dependencies
pip install --upgrade -r tests/requirements.txt
- name: Install Playwright browser
run: python -m playwright install chromium --with-deps
- name: Test SABnzbd
run: pytest -s
run: pytest -n auto --dist loadscope
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
if: github.repository_owner == 'sabnzbd'
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v10
- uses: actions/stale@v11
with:
days-before-stale: 21
days-before-close: 7
+1
View File
@@ -16,6 +16,7 @@ jobs:
translations:
name: Update translatable texts
runs-on: ubuntu-latest
timeout-minutes: 10
env:
TX_TOKEN: ${{ secrets.TX_TOKEN }}
steps:
+3 -3
View File
@@ -16,7 +16,7 @@ jobs:
if: github.repository == 'sabnzbd/sabnzbd'
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ github.token }}
GH_TOKEN: ${{ secrets.AUTOMATION_GITHUB_TOKEN }}
BRANCH: automation/update-unrar
steps:
- uses: actions/checkout@v7
@@ -83,7 +83,7 @@ jobs:
if: github.repository == 'sabnzbd/sabnzbd'
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ github.token }}
GH_TOKEN: ${{ secrets.AUTOMATION_GITHUB_TOKEN }}
BRANCH: automation/update-7zip
steps:
- uses: actions/checkout@v7
@@ -144,7 +144,7 @@ jobs:
if: github.repository == 'sabnzbd/sabnzbd'
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ github.token }}
GH_TOKEN: ${{ secrets.AUTOMATION_GITHUB_TOKEN }}
BRANCH: automation/update-par2
steps:
- uses: actions/checkout@v7
+1
View File
@@ -32,6 +32,7 @@ SABnzbd-*/
# Testing folders
tests/cache
tests/cache_gw*
# General junk
*.keep
-50
View File
@@ -1,50 +0,0 @@
*******************************************
*** Known issues ***
*******************************************
- To prevent unexpectedly large NZBs from eating your download quota you can set
the option 'size_limit' on the Config->Special page.
Any NZB larger than this size will be set to paused and get a low priority.
- When par2 or unrar hang up, never just stop SABnzbd.
Instead use your operating system's task manager to stop the par2 or unrar program.
Forcing SABnzbd to quit may damage your queues.
- Some Usenet servers have intermittent login (or other) problems.
For these the server blocking method is not very favourable.
There is an INI-only option that will limit blocks to 1 minute.
no_penalties = 1
See: https://sabnzbd.org/wiki/configuration/3.4/special
- Some third-party utilities try to probe SABnzbd API in such a way that you will
often see warnings about unauthenticated access.
If you are sure these probes are harmless, you can suppress the warnings by
setting the option "api_warnings" to 0.
See: https://sabnzbd.org/wiki/configuration/3.4/special
- On macOS you may encounter downloaded files with foreign characters.
The par2 repair may fail when the files were created on a Windows system.
The problem is caused by the PAR2 utility and we cannot fix this now.
This does not apply to files inside RAR files.
- The "Watched Folder" sometimes fails to delete the NZB files it has
processed. This happens when other software still accesses these files.
Some third-party utilities supporting SABnzbd are known to do this.
We cannot solve this problem, because the Operating System (read Windows)
prevents the removal.
- When SABnzbd cannot send notification emails, check your virus scanner,
firewall or security suite. It may be blocking outgoing email.
- When you are using external drives or network shares on macOS or Linux
make sure that the drives are mounted.
The operating system will simply redirect your files to alternative locations.
You may have trouble finding the files when mounting the drive later.
On macOS, SABnzbd will not create new folders in /Volumes.
The result will be a failed job that can be retried once the volume has been mounted.
- If you use a mounted drive as "temporary download folder", it must be present when SABnzbd
starts up. If not, SABnzbd will use the default location.
You can make SABnzbd wait for a mount of the "temporary download folder" by setting
Config->Special->wait_for_dfolder to 1.
SABnzbd will appear to hang until the drive is mounted.
+8 -8
View File
@@ -1,9 +1,7 @@
Release Notes - SABnzbd 5.1.0 Release Candidate 1
Release Notes - SABnzbd 5.1.0 Release Candidate 2
=========================================================
This is the first release candidate of version 5.1.
Like many other projects out there, we were able to use the
shiny new AI tools to add quite a lot of long-requested features!
This is the second release candidate of version 5.1.
## New features in 5.1.0
@@ -22,8 +20,10 @@ shiny new AI tools to add quite a lot of long-requested features!
listing all files that resulted from the job.
* New Servers will default to 16 connections instead of 8.
* Use media duration as part of `Ignore Samples` detection.
* Added option to (auto) sort the queue by Remaining Percentage.
* Improved support for screen readers.
* Parsing of header-encrypted RARs will use significantly fewer resources.
* Add Ayatana AppIndicator tray support on GNOME.
* Removed redundant `INSTALL.txt` file.
* Dropped support for Python 3.9.
* Windows and macOS: Updated Python to 3.14.6, Unrar to 7.23 and 7zip to 26.02.
@@ -35,6 +35,10 @@ shiny new AI tools to add quite a lot of long-requested features!
* Prevent path traversal in orphaned job APIs.
* `Disk Full` errors from unrar were not handled gracefully during unpacking.
* Memory leak could occur during article decoding.
* In containers (like Docker), the Article Cache could exceed the memory limit.
* Diskspace checks would be too strict when unpacking to different disk.
* Prevent deadlock when a second signal arrives during shutdown procedure.
* Verification using SFV-checks could fail, even though files were correct.
* Windows: Uninstall would not remove Settings or Windows Service.
* Windows: Warn for OS-limit if more than 1024 connections are configured.
* macOS: AppleDouble files could result in failures in `Moving` stage.
@@ -45,10 +49,6 @@ shiny new AI tools to add quite a lot of long-requested features!
* You can directly upgrade from version 3.0.0 and newer.
* Upgrading from older versions will require performing a `Queue repair`.
## Known problems and solutions
* Read `ISSUES.txt` or https://sabnzbd.org/wiki/introduction/known-issues
## Code Signing Policy
Windows code signing is provided by SignPath.io using a SignPath Foundation certificate.
+132 -224
View File
@@ -40,7 +40,6 @@ import time
import re
import gc
import threading
import http.cookies
from typing import Any
try:
@@ -48,9 +47,7 @@ try:
import Cheetah
import feedparser
import configobj
import cherrypy
import cheroot.errors
import portend
import uvicorn
import cryptography
import charset_normalizer
import guessit
@@ -69,6 +66,7 @@ import sabnzbd.interface
from sabnzbd.constants import (
DEF_NETWORKING_TIMEOUT,
DEF_LOG_ERRFILE,
DEF_LOG_ACCESSFILE,
DEF_MAIN_TMPL,
DEF_STD_WEB_DIR,
DEF_WORKDIR,
@@ -81,13 +79,17 @@ from sabnzbd.constants import (
RSS_FILE_NAME,
DEF_LOG_FILE,
DEF_STD_CONFIG,
DEF_LOG_CHERRY,
CONFIG_BACKUP_HTTPS,
)
import sabnzbd.newsunpack
from sabnzbd.misc import (
exit_sab,
split_host,
port_is_free,
find_free_port,
bind_web_socket,
HostNotAvailableError,
xff_trusted_networks,
create_https_certificates,
ip_extract,
set_serv_parms,
@@ -99,7 +101,7 @@ from sabnzbd.misc import (
set_https_verification,
)
from sabnzbd.filesystem import get_ext, real_path, long_path, globber_full, remove_file
from sabnzbd.panic import panic_tmpl, panic_port, panic_host, panic, launch_a_browser
from sabnzbd.panic import panic_tmpl, panic_port, panic_port_permission, panic_host, panic, launch_a_browser
import sabnzbd.config as config
import sabnzbd.cfg
import sabnzbd.notifier as notifier
@@ -205,7 +207,7 @@ def print_help():
print(" -t --templates <templ> Template directory [*]")
print()
print(" -l --logging <-1..2> Set logging level (-1=off, 0=least,2= most) [*]")
print(" -w --weblogging Enable cherrypy access logging")
print(" -w --weblogging Enable uvicorn access logging")
print()
print(" -b --browser <0..1> Auto browser launch (0= off, 1= on) [*]")
if sabnzbd.WINDOWS:
@@ -291,18 +293,41 @@ def daemonize():
os.dup2(f.fileno(), sys.stderr.fileno())
def abort_and_show_error(browserhost, web_port, err=""):
"""Abort program because of CherryPy troubles"""
def abort_and_show_error(browserhost, web_port, err="", panic_func=panic_port):
"""Abort program because the web-interface could not be started"""
logging.error(T("Failed to start web-interface") + " : " + str(err))
if not sabnzbd.DAEMON:
if "49" in err:
panic_host(browserhost, web_port)
else:
panic_port(browserhost, web_port)
panic_func(browserhost, web_port)
sabnzbd.halt()
exit_sab(2)
def abort_for_unusable_address(browserhost, port, err):
"""Abort with the panic that matches why the address could not be used"""
if isinstance(err, PermissionError):
abort_and_show_error(browserhost, port, err, panic_func=panic_port_permission)
else:
abort_and_show_error(browserhost, port, err, panic_func=panic_host)
def port_is_free_or_abort(host, port, browserhost):
"""port_is_free(), but abort when the address cannot be used at all. Saying so
up front beats a search that can only fail, followed by a message claiming
some other program holds the port."""
try:
return port_is_free(host, port)
except (PermissionError, HostNotAvailableError) as err:
abort_for_unusable_address(browserhost, port, err)
def find_free_port_or_abort(host, currentport, browserhost):
"""find_free_port(), but abort when the address cannot be used at all"""
try:
return find_free_port(host, currentport)
except (PermissionError, HostNotAvailableError) as err:
abort_for_unusable_address(browserhost, currentport, err)
def identify_web_template(key, defweb, wdir):
"""Determine a correct web template set, return full template path"""
if wdir is None:
@@ -652,19 +677,6 @@ def get_webhost(web_host, web_port, https_port):
return web_host, web_port, browserhost, https_port
def attach_server(host, port, cert=None, key=None, chain=None):
"""Define and attach server, optionally HTTPS"""
if sabnzbd.cfg.ipv6_hosting() or "::1" not in host:
http_server = cherrypy._cpserver.Server()
http_server.bind_addr = (host, port)
if cert and key:
http_server.ssl_module = "builtin"
http_server.ssl_certificate = cert
http_server.ssl_private_key = key
http_server.ssl_certificate_chain = chain
http_server.subscribe()
def is_sabnzbd_running(url):
"""Return True when there's already a SABnzbd instance running."""
try:
@@ -678,19 +690,6 @@ def is_sabnzbd_running(url):
return False
def find_free_port(host, currentport):
"""Return a free port, 0 when nothing is free"""
n = 0
while n < 10 and currentport <= 49151:
try:
portend.free(host, currentport, timeout=0.025)
return currentport
except Exception:
currentport += 5
n += 1
return 0
def check_for_sabnzbd(url, upload_nzbs, allow_browser=True):
"""Check for a running instance of sabnzbd on this port
allow_browser==True|None will launch the browser, False will not.
@@ -837,7 +836,7 @@ def main():
web_host = None
web_port = None
https_port = None
cherrypylogging = None
weblogging = None
clean_up = False
logging_level = None
console_logging = False
@@ -883,7 +882,7 @@ def main():
elif opt in ("-c", "--clean"):
clean_up = True
elif opt in ("-w", "--weblogging"):
cherrypylogging = True
weblogging = True
elif opt in ("-l", "--logging"):
try:
logging_level = int(arg)
@@ -1002,78 +1001,54 @@ def main():
# When this is a daemon, just check and bail out if port in use
if sabnzbd.DAEMON:
if enable_https and https_port:
try:
portend.free(web_host, https_port, timeout=0.05)
except IOError:
if not port_is_free_or_abort(web_host, https_port, browserhost):
abort_and_show_error(browserhost, web_port)
except Exception:
abort_and_show_error(browserhost, web_port, "49")
try:
portend.free(web_host, web_port, timeout=0.05)
except IOError:
if not port_is_free_or_abort(web_host, web_port, browserhost):
abort_and_show_error(browserhost, web_port)
except Exception:
abort_and_show_error(browserhost, web_port, "49")
# Windows instance is reachable through registry
url = None
if sabnzbd.WINDOWS and not new_instance:
url = get_connection_info()
url = get_connection_info(inifile)
if url and check_for_sabnzbd(url, upload_nzbs, autobrowser):
exit_sab(0)
# SSL
if enable_https:
port = https_port or web_port
try:
portend.free(browserhost, port, timeout=0.05)
except IOError as error:
if str(error) == "Port not bound.":
pass
else:
if not url:
url = "https://%s:%s%s/api?" % (browserhost, port, sabnzbd.cfg.url_base())
if new_instance or not check_for_sabnzbd(url, upload_nzbs, autobrowser):
# Bail out if we have fixed our ports after first start-up
if sabnzbd.cfg.fixed_ports():
abort_and_show_error(browserhost, web_port)
# Find free port to bind
newport = find_free_port(browserhost, port)
if newport > 0:
# Save the new port
if https_port:
https_port = newport
sabnzbd.cfg.https_port.set(newport)
else:
# In case HTTPS == HTTP port
web_port = newport
sabnzbd.cfg.web_port.set(newport)
except Exception:
# Something else wrong, probably badly specified host
abort_and_show_error(browserhost, web_port, "49")
if not port_is_free_or_abort(web_host, port, browserhost):
if not url:
url = "https://%s:%s%s/api?" % (browserhost, port, sabnzbd.cfg.url_base())
if new_instance or not check_for_sabnzbd(url, upload_nzbs, autobrowser):
# Bail out if we have fixed our ports after first start-up
if sabnzbd.cfg.fixed_ports():
abort_and_show_error(browserhost, web_port)
# Find free port to bind
newport = find_free_port_or_abort(web_host, port, browserhost)
if newport:
# Save the new port
if https_port:
https_port = newport
sabnzbd.cfg.https_port.set(newport)
else:
# In case HTTPS == HTTP port
web_port = newport
sabnzbd.cfg.web_port.set(newport)
# NonSSL check if there's no HTTPS or we only use 1 port
if not (enable_https and not https_port):
try:
portend.free(browserhost, web_port, timeout=0.05)
except IOError as error:
if str(error) == "Port not bound.":
pass
else:
if not url:
url = "http://%s:%s%s/api?" % (browserhost, web_port, sabnzbd.cfg.url_base())
if new_instance or not check_for_sabnzbd(url, upload_nzbs, autobrowser):
# Bail out if we have fixed our ports after first start-up
if sabnzbd.cfg.fixed_ports():
abort_and_show_error(browserhost, web_port)
# Find free port to bind
port = find_free_port(browserhost, web_port)
if port > 0:
sabnzbd.cfg.web_port.set(port)
web_port = port
except Exception:
# Something else wrong, probably badly specified host
abort_and_show_error(browserhost, web_port, "49")
if not port_is_free_or_abort(web_host, web_port, browserhost):
if not url:
url = "http://%s:%s%s/api?" % (browserhost, web_port, sabnzbd.cfg.url_base())
if new_instance or not check_for_sabnzbd(url, upload_nzbs, autobrowser):
# Bail out if we have fixed our ports after first start-up
if sabnzbd.cfg.fixed_ports():
abort_and_show_error(browserhost, web_port)
# Find free port to bind
port = find_free_port_or_abort(web_host, web_port, browserhost)
if port:
sabnzbd.cfg.web_port.set(port)
web_port = port
# We found a port, now we never check again
sabnzbd.cfg.fixed_ports.set(True)
@@ -1111,6 +1086,9 @@ def main():
rollover_log = logging.handlers.RotatingFileHandler(
sabnzbd.LOGFILE, "a+", sabnzbd.cfg.log_size(), sabnzbd.cfg.log_backups()
)
# Set the level here as well as on the logger, so records that were
# created at a higher level and lowered afterwards are also dropped
rollover_log.setLevel(LOGLEVELS[logging_level + 1])
rollover_log.setFormatter(logging.Formatter(logformat))
logger.addHandler(rollover_log)
@@ -1172,7 +1150,7 @@ def main():
if sabnzbd.cfg.tray_icon() and not sabnzbd.DAEMON and not sabnzbd.WIN_SERVICE:
if sabnzbd.WINDOWS:
sabnzbd.WINTRAY = sabnzbd.sabtraywin.SABTrayThread()
elif sabnzbd.LINUX_POWER and os.environ.get("DISPLAY"):
elif sabnzbd.LINUX_POWER and (os.environ.get("DISPLAY") or os.environ.get("XDG_CURRENT_DESKTOP")):
try:
import gi
@@ -1219,41 +1197,14 @@ def main():
# Starting of the webserver
# Determine if this system has multiple definitions for 'localhost'
hosts = all_localhosts()
multilocal = len(hosts) > 1 and web_host in ("localhost", "0.0.0.0")
# For 0.0.0.0 CherryPy will always pick IPv4, so make sure the secondary localhost is IPv6
if multilocal and web_host == "0.0.0.0" and hosts[1] == "127.0.0.1":
hosts[1] = "::1"
# The Windows binary requires numeric localhost as primary address
if web_host == "localhost":
web_host = hosts[0]
if enable_https:
if https_port:
# Extra HTTP port for primary localhost
attach_server(web_host, web_port)
if multilocal:
# Extra HTTP port for secondary localhost
attach_server(hosts[1], web_port)
# Extra HTTPS port for secondary localhost
attach_server(hosts[1], https_port, https_cert, https_key, https_chain)
web_port = https_port
elif multilocal:
# Extra HTTPS port for secondary localhost
attach_server(hosts[1], web_port, https_cert, https_key, https_chain)
cherrypy.config.update(
{
"server.ssl_module": "builtin",
"server.ssl_certificate": https_cert,
"server.ssl_private_key": https_key,
"server.ssl_certificate_chain": https_chain,
}
)
elif multilocal:
# Extra HTTP port for secondary localhost
attach_server(hosts[1], web_port)
if enable_https and https_port:
# Separate HTTPS port: switch the main server to the HTTPS port
web_port = https_port
if no_login:
sabnzbd.cfg.username.set("")
@@ -1263,108 +1214,55 @@ def main():
if inet_exposure:
sabnzbd.cfg.inet_exposure.set(inet_exposure)
mime_gzip = (
"text/*",
"application/javascript",
"application/x-javascript",
"application/json",
"application/xml",
"application/vnd.ms-fontobject",
"application/font*",
"image/svg+xml",
)
cherrypy.config.update(
{
"server.environment": "production",
"server.socket_host": web_host,
"server.socket_port": web_port,
"server.shutdown_timeout": 0,
"engine.autoreload.on": False,
"tools.encode.on": True,
"tools.gzip.on": True,
"tools.gzip.mime_types": mime_gzip,
"error_page.401": sabnzbd.panic.error_page_401,
"error_page.404": sabnzbd.panic.error_page_404,
}
)
# Monkey-patch key validation to prevent cherrypy from stumbling over invalid cookies
http.cookies._is_legal_key = lambda _: True
# Catch shutdown errors that can break cherrypy/cheroot
# See https://github.com/cherrypy/cheroot/issues/710
try:
cheroot.errors.acceptable_sock_shutdown_exceptions += (OSError,)
except AttributeError:
pass
# Do we want CherryPy Logging? Cannot be done via the config
cherrypy.log.screen = False
cherrypy.log.access_log.propagate = False
if cherrypylogging:
sabnzbd.WEBLOGFILE = os.path.join(logdir, DEF_LOG_CHERRY)
cherrypy.log.access_file = str(sabnzbd.WEBLOGFILE)
# Force mimetypes (OS might overwrite them)
forced_mime_types = {"css": "text/css", "js": "application/javascript"}
static = {
"tools.staticdir.on": True,
"tools.staticdir.dir": os.path.join(sabnzbd.WEB_DIR, "static"),
"tools.staticdir.content_types": forced_mime_types,
}
staticcfg = {
"tools.staticdir.on": True,
"tools.staticdir.dir": os.path.join(sabnzbd.WEB_DIR_CONFIG, "staticcfg"),
"tools.staticdir.content_types": forced_mime_types,
}
wizard_static = {
"tools.staticdir.on": True,
"tools.staticdir.dir": os.path.join(sabnzbd.WIZARD_DIR, "static"),
"tools.staticdir.content_types": forced_mime_types,
}
appconfig = {
"/api": {
"tools.auth_basic.on": False,
"tools.response_headers.on": True,
"tools.response_headers.headers": [("Access-Control-Allow-Origin", "*")],
},
"/static": static,
"/wizard/static": wizard_static,
"/favicon.ico": {
"tools.staticfile.on": True,
"tools.staticfile.filename": os.path.join(sabnzbd.WEB_DIR_CONFIG, "staticcfg", "ico", "favicon.ico"),
},
"/staticcfg": staticcfg,
}
# Make available from both URLs
main_page = sabnzbd.interface.MainPage()
cherrypy.Application.relative_urls = "server"
cherrypy.tree.mount(main_page, "/", config=appconfig)
cherrypy.tree.mount(main_page, sabnzbd.cfg.url_base(), config=appconfig)
# Set authentication for CherryPy
sabnzbd.interface.set_auth(cherrypy.config)
logging.info("Starting web-interface on %s:%s", web_host, web_port)
sabnzbd.cfg.log_level.callback(guard_loglevel)
try:
cherrypy.engine.start()
except Exception:
# Since the webserver is started by cherrypy in a separate thread, we can't really catch any
# start-up errors. This try/except only catches very few errors, the rest is only shown in the console.
logging.error(T("Failed to start web-interface: "), exc_info=True)
abort_and_show_error(browserhost, web_port)
# Create a record of the active cert/key/chain files, for use with config.create_config_backup()
if enable_https:
for setting in CONFIG_BACKUP_HTTPS.values():
if full_path := getattr(sabnzbd.cfg, setting).get_path():
sabnzbd.CONFIG_BACKUP_HTTPS_OK.append(full_path)
# Do we want web-server access logging? Cannot be done via the config
if weblogging:
sabnzbd.WEBLOGFILE = os.path.join(logdir, DEF_LOG_ACCESSFILE)
# Catch logging using SABnzbd handlers
uvicorn_logging_config = sabnzbd.interface.uvicorn_logging_config(sabnzbd.WEBLOGFILE)
# Claim the port here rather than letting uvicorn do it, because this is the
# first point where the host and port are final. Everything before this was
# only picking a port, and anything could still have taken it since.
try:
web_socket = bind_web_socket(web_host, web_port)
except (PermissionError, HostNotAvailableError) as err:
abort_for_unusable_address(browserhost, web_port, err)
except OSError as err:
logging.error(T("Failed to start web-interface: "), exc_info=True)
abort_and_show_error(browserhost, web_port, err)
server_config = uvicorn.Config(
sabnzbd.interface.create_app(),
host=web_host,
port=web_port,
log_config=uvicorn_logging_config,
ssl_keyfile=https_key if enable_https else None,
ssl_certfile=https_cert if enable_https else None,
ssl_ca_certs=https_chain if enable_https else None,
proxy_headers=bool(sabnzbd.cfg.verify_xff_header()),
forwarded_allow_ips=xff_trusted_networks(),
)
sabnzbd.WEB_SERVER = sabnzbd.interface.ThreadedServer(config=server_config, sockets=[web_socket])
try:
sabnzbd.WEB_SERVER.run_in_thread()
except Exception:
# The webserver runs in a separate thread; if it fails to start (bad cert,
# unusable TLS material) surface the error and abort instead of hanging.
# Details are also shown on the console.
logging.error(T("Failed to start web-interface: "), exc_info=True)
abort_and_show_error(browserhost, web_port)
# Set URL for browser
if enable_https:
sabnzbd.BROWSER_URL = "https://%s:%s%s" % (browserhost, web_port, sabnzbd.cfg.url_base())
@@ -1373,7 +1271,7 @@ def main():
if sabnzbd.WINDOWS:
# Write URL for uploads and version check directly to registry
set_connection_info(f"{sabnzbd.BROWSER_URL}/api?apikey={sabnzbd.cfg.api_key()}")
set_connection_info(f"{sabnzbd.BROWSER_URL}/api?apikey={sabnzbd.cfg.api_key()}", inifile)
if pid_path or pid_file:
sabnzbd.pid_file(pid_path, pid_file, web_port)
@@ -1421,6 +1319,8 @@ def main():
logger.setLevel(level)
if console_logging:
console.setLevel(level)
if not no_file_log:
rollover_log.setLevel(level)
# 300 sec polling tasks
if not timer % 100:
@@ -1482,13 +1382,21 @@ def main():
# Just a simple restart of the exe
os.execv(sys.executable, ['"%s"' % arg for arg in sys.argv])
else:
# CherryPy has special logic to include interpreter options such as "-OO"
cherrypy.engine._do_execv()
# Re-exec with interpreter flags (replaces cherrypy.engine._do_execv)
args = [sys.executable]
if sys.flags.optimize == 1:
args.append("-O")
elif sys.flags.optimize >= 2:
args.append("-OO")
args.extend(sys.argv)
os.execv(sys.executable, args)
# Send our final goodbyes!
notifier.send_notification("SABnzbd", T("SABnzbd shutdown finished"), "startup")
logging.info("Leaving SABnzbd")
sabnzbd.pid_file()
if sabnzbd.WEB_SERVER:
sabnzbd.WEB_SERVER.stop()
try:
sys.stderr.flush()
+1 -1
View File
@@ -13,7 +13,7 @@ from builder.common import EXTRA_FILES, EXTRA_FOLDERS, RELEASE_VERSION, RELEASE_
extra_pyinstaller_files = []
# Add hidden imports
extra_hiddenimports = ["Cheetah.DummyTransaction", "cheroot.ssl.builtin", "certifi"]
extra_hiddenimports = ["Cheetah.DummyTransaction", "certifi"]
extra_hiddenimports.extend(collect_submodules("apprise"))
extra_hiddenimports.extend(collect_submodules("babelfish.converters"))
extra_hiddenimports.extend(collect_submodules("guessit.data"))
-1
View File
@@ -63,7 +63,6 @@ EXTRA_FILES = [
"GPL2.txt",
"GPL3.txt",
"COPYRIGHT.txt",
"ISSUES.txt",
]
EXTRA_FOLDERS = [
"scripts/",
+1 -1
View File
@@ -246,7 +246,7 @@ def test_sab_binary(binary_path: str):
# Parse API-key so we can do a graceful shutdown
sab_config = configobj.ConfigObj(os.path.join(config_dir, "sabnzbd.ini"))
urllib.request.urlopen(base_url + "shutdown/?apikey=" + sab_config["misc"]["api_key"], timeout=10)
urllib.request.urlopen(base_url + "api?mode=shutdown&apikey=" + sab_config["misc"]["api_key"], timeout=10)
sabnzbd_process.wait()
# Print logs for verification
+7 -7
View File
@@ -1,13 +1,13 @@
# All sub-dependencies are listed below and installed with --no-dependencies for security
PyGithub==2.9.1
praw==8.0.2
PyGithub==2.10.0
praw==8.0.3
pefile==2024.8.26
# PyGithub dependencies
pynacl==1.6.2
requests==2.34.2
pyjwt==2.13.0
typing-extensions==4.15.0
typing-extensions==4.16.0
urllib3==2.7.0
# praw dependencies
@@ -17,11 +17,11 @@ update-checker==1.0.0
websocket-client==1.9.0
# requests dependencies
charset_normalizer==3.4.7
idna==3.18
certifi==2026.6.17
charset_normalizer==3.5.1
idna==3.19
certifi==2026.7.22
# cryptography (via pyjwt[crypto]) dependencies
cryptography==49.0.0
cffi==2.0.0
cffi==2.1.1
pycparser==3.0
+43
View File
@@ -21,6 +21,7 @@ import re
import github
import praw
import requests
from common import (
RELEASE_VERSION,
@@ -186,6 +187,20 @@ if RELEASE_THIS and gh_token:
print("Merging pull request in sabnzbd/sabnzbd.github.io for the update")
update_pr.merge(merge_method="squash")
# Trigger the Docker image build at linuxserver.io
# Branch "develop" builds the pre-releases, "master" the stable releases
if linuxserver_token := os.environ.get("LINUXSERVER_WEBHOOK_TOKEN", ""):
linuxserver_branch = "develop" if PRERELEASE else "master"
print("Triggering linuxserver.io Docker build for branch %s" % linuxserver_branch)
requests.post(
"https://ci.linuxserver.io/generic-webhook-trigger/invoke?sabnzbd",
headers={"Authorization": "Bearer %s" % linuxserver_token},
json={"branch": linuxserver_branch},
timeout=30,
).raise_for_status()
else:
print("Missing LINUXSERVER_WEBHOOK_TOKEN")
# Only with GitHub success we proceed to Reddit
if reddit_token := os.environ.get("REDDIT_TOKEN", ""):
# Token format (without whitespace):
@@ -233,6 +248,34 @@ if RELEASE_THIS and gh_token:
else:
print("Missing REDDIT_TOKEN")
# Push release notes to Discord via an incoming webhook
# Separate channels for testing (pre-release) and stable, both are required
discord_webhook_testing = os.environ.get("DISCORD_WEBHOOK_TESTING", "")
discord_webhook_stable = os.environ.get("DISCORD_WEBHOOK_STABLE", "")
if discord_webhook_testing and discord_webhook_stable:
discord_webhook = discord_webhook_testing if PRERELEASE else discord_webhook_stable
print("Posting release notes to Discord")
# Reuse the release notes read earlier: line 0 is the title header
discord_lines = readme_data.splitlines(keepends=True)
discord_title = discord_lines[0].lstrip("# ").strip()
discord_body = "".join(discord_lines[2:])[:4096]
requests.post(
discord_webhook,
json={
"embeds": [
{
"title": discord_title,
"url": gh_release.html_url,
"description": discord_body,
"color": 0xFFA500 if PRERELEASE else 0x00A550,
}
]
},
timeout=30,
).raise_for_status()
else:
print("Missing DISCORD_WEBHOOK_TESTING and/or DISCORD_WEBHOOK_STABLE")
else:
print("To push release to GitHub, first tag the commit.")
print("Or missing the AUTOMATION_GITHUB_TOKEN, cannot push to GitHub without it.")
+5 -5
View File
@@ -1,11 +1,11 @@
# All sub-dependencies are listed below and installed with --no-dependencies for security
pyinstaller==6.21.0
packaging==26.2
pyinstaller==6.22.2
packaging==26.3
pyinstaller-hooks-contrib==2026.6
altgraph==0.17.5
wrapt==2.2.2
setuptools==82.0.1
markdown==3.10.2
wrapt==2.3.0
setuptools==84.0.0
markdown==3.10.3
pefile==2024.8.26
# For the Windows build
@@ -2,12 +2,12 @@
<div class="clearfix"></div>
<!-- Filebrowser modal -->
<div class="modal fade" id="filebrowser_modal">
<div class="modal fade" id="filebrowser_modal" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="filebrowser-modal-title">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title"></h4>
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="filebrowser-modal-title"></h4>
</div>
<div class="modal-body">
</div>
@@ -33,4 +33,4 @@
</div>
</div>
</body>
</html>
</html>
+28 -36
View File
@@ -1,10 +1,5 @@
#if $pane == "Config"#
#set global $root = '../'#
#else#
#set global $root = '../../'#
#end if#
<!DOCTYPE HTML>
<html lang="$active_lang" #if $rtl#dir="rtl"#end if#>
<html lang="$active_lang" #if $rtl#dir="rtl"#end if# data-color-scheme="$color_scheme">
<head>
<title>
SABnzbd $T('menu-config')
@@ -14,7 +9,7 @@
#if $pane == "Switches" then $T('cmenu-switches') else ""#
#if $pane == "Servers" then $T('cmenu-servers') else ""#
#if $pane == "Scheduling" then $T('cmenu-scheduling') else ""#
#if $pane == "Email" then $T('cmenu-notif') else ""#
#if $pane == "Notify" then $T('cmenu-notif') else ""#
#if $pane == "Categories" then $T('cmenu-cat') else ""#
#if $pane == "Sorting" then $T('cmenu-sorting') else ""#
#if $pane == "Special" then $T('cmenu-special') else ""#
@@ -25,20 +20,17 @@
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, maximum-scale=1" />
<meta name="apple-mobile-web-app-title" content="SABnzbd" />
<link rel="apple-touch-icon" sizes="76x76" href="${root}staticcfg/ico/apple-touch-icon-76x76-precomposed.png" />
<link rel="apple-touch-icon" sizes="120x120" href="${root}staticcfg/ico/apple-touch-icon-120x120-precomposed.png" />
<link rel="apple-touch-icon" sizes="152x152" href="${root}staticcfg/ico/apple-touch-icon-152x152-precomposed.png" />
<link rel="apple-touch-icon" sizes="180x180" href="${root}staticcfg/ico/apple-touch-icon-180x180-precomposed.png" />
<link rel="apple-touch-icon" sizes="192x192" href="${root}staticcfg/ico/android-192x192.png" />
<link rel="apple-touch-icon" sizes="76x76" href="$url('staticcfg/ico/apple-touch-icon-76x76-precomposed.png', v=$cache_buster)" />
<link rel="apple-touch-icon" sizes="120x120" href="$url('staticcfg/ico/apple-touch-icon-120x120-precomposed.png', v=$cache_buster)" />
<link rel="apple-touch-icon" sizes="152x152" href="$url('staticcfg/ico/apple-touch-icon-152x152-precomposed.png', v=$cache_buster)" />
<link rel="apple-touch-icon" sizes="180x180" href="$url('staticcfg/ico/apple-touch-icon-180x180-precomposed.png', v=$cache_buster)" />
<link rel="apple-touch-icon" sizes="192x192" href="$url('staticcfg/ico/android-192x192.png', v=$cache_buster)" />
<link rel="stylesheet" type="text/css" href="${root}staticcfg/bootstrap/css/bootstrap.min.css?v=$cache_buster" />
<link rel="stylesheet" type="text/css" href="${root}staticcfg/css/chartist.min.css?v=$cache_buster" />
<link rel="stylesheet" type="text/css" href="${root}staticcfg/css/style.css?v=$cache_buster" />
<!--#if $color_scheme not in ('Light', '') #-->
<link rel="stylesheet" type="text/css" href="${root}staticcfg/css/${color_scheme}.css?v=$cache_buster"/>
<!--#end if#-->
<link rel="stylesheet" type="text/css" href="$url('staticcfg/bootstrap/css/bootstrap.min.css', v=$cache_buster)" />
<link rel="stylesheet" type="text/css" href="$url('staticcfg/css/chartist.min.css', v=$cache_buster)" />
<link rel="stylesheet" type="text/css" href="$url('staticcfg/css/style.css', v=$cache_buster)" />
<link rel="shortcut icon" href="${root}staticcfg/ico/favicon.ico?v=$cache_buster" />
<link rel="shortcut icon" href="$url('staticcfg/ico/favicon.ico', v=$cache_buster)" />
<script type="text/javascript">
// Keeping track of the form state
@@ -46,10 +38,10 @@
var formWasSubmitted = false;
// Information we need
var sabSession = '$apikey';
var rootURL = '${root}'
var csrfToken = '$csrf_token';
var rootURL = '$url()'
var urlBase = '${url_base}'
var folderBrowseUrl = '${root}api?mode=browse&output=json&apikey=$apikey';
var folderBrowseUrl = "$url('api', mode='browse', output='json')";
var folderSeperator = '#if $os.sep == '\\' then '\\\\' else '/'#'
// Translations
@@ -65,9 +57,9 @@
configTranslate.confirmLeave = "$T('confirmWithoutSavingPrompt')";
configTranslate.searchPages = ['$T('cmenu-general')', '$T('cmenu-folders')', '$T('cmenu-switches')', '$T('cmenu-sorting')', '$T('cmenu-notif')', '$T('cmenu-special')']
</script>
<script type="text/javascript" src="${root}staticcfg/js/jquery-3.5.1.min.js?v=$cache_buster"></script>
<script type="text/javascript" src="${root}staticcfg/bootstrap/js/bootstrap.min.js?v=$cache_buster"></script>
<script type="text/javascript" src="${root}staticcfg/js/script.js?v=$cache_buster"></script>
<script type="text/javascript" src="$url('staticcfg/js/jquery-3.7.1.min.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('staticcfg/bootstrap/js/bootstrap.min.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('staticcfg/js/script.js', v=$cache_buster)"></script>
<script type="text/javascript">
// Set default functions for the autocomplete everywhere
@@ -92,62 +84,62 @@
<span class="icon-bar"></span>
</button>
<a class="navbar-logo navbar-logo-small" href="${root}" title="$T('Home')" data-placement="bottom">
<a class="navbar-logo navbar-logo-small" href="$url()" title="$T('Home')" data-placement="bottom">
#include $webdir + "/staticcfg/images/logo-small.svg"#
</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>
<a href="${root}config/general/" #if $pane == "General" then 'class="active"' else ""#>
<a href="$url('config/general')" #if $pane == "General" then 'class="active"' else ""#>
<span class="glyphicon glyphicon-cog"></span>
<strong>$T('cmenu-general')</strong>
</a>
</li>
<li>
<a href="${root}config/folders/" #if $pane == "Folders" then 'class="active"' else ""#>
<a href="$url('config/folders')" #if $pane == "Folders" then 'class="active"' else ""#>
<span class="glyphicon glyphicon-folder-open"></span>
<strong>$T('cmenu-folders')</strong>
</a>
</li>
<li>
<a href="${root}config/server/" #if $pane == "Servers" then 'class="active"' else ""#>
<a href="$url('config/server')" #if $pane == "Servers" then 'class="active"' else ""#>
<span class="glyphicon glyphicon-sort"></span>
<strong>$T('cmenu-servers')</strong>
</a>
</li>
<li>
<a href="${root}config/categories/" #if $pane == "Categories" then 'class="active"' else ""#>
<a href="$url('config/categories')" #if $pane == "Categories" then 'class="active"' else ""#>
<span class="glyphicon glyphicon-tag"></span>
<strong>$T('cmenu-cat')</strong>
</a>
</li>
<li>
<a href="${root}config/switches/" #if $pane == "Switches" then 'class="active"' else ""#>
<a href="$url('config/switches')" #if $pane == "Switches" then 'class="active"' else ""#>
<span class="glyphicon glyphicon-check"></span>
<strong>$T('cmenu-switches')</strong>
</a>
</li>
<li>
<a href="${root}config/sorting/" #if $pane == "Sorting" then 'class="active"' else ""#>
<a href="$url('config/sorting')" #if $pane == "Sorting" then 'class="active"' else ""#>
<span class="glyphicon glyphicon-sort-by-alphabet"></span>
<strong>$T('cmenu-sorting')</strong>
</a>
</li>
<li>
<a href="${root}config/notify/" #if $pane == "Email" then 'class="active"' else ""#>
<a href="$url('config/notify')" #if $pane == "Notify" then 'class="active"' else ""#>
<span class="glyphicon glyphicon-comment"></span>
<strong>$T('cmenu-notif')</strong>
</a>
</li>
<li>
<a href="${root}config/scheduling/" #if $pane == "Scheduling" then 'class="active"' else ""#>
<a href="$url('config/scheduling')" #if $pane == "Scheduling" then 'class="active"' else ""#>
<span class="glyphicon glyphicon-time"></span>
<strong>$T('cmenu-scheduling')</strong>
</a>
</li>
<li>
<a href="${root}config/rss/" #if $pane == "RSS" then 'class="active"' else ""#>
<a href="$url('config/rss')" #if $pane == "RSS" then 'class="active"' else ""#>
<svg class="rss-icon-svg" viewBox="0 0 8 8">
<rect class="rss-button" width="8" height="8" />
<circle class="rss-symbol" cx="2" cy="6" r="1" />
@@ -158,7 +150,7 @@
</a>
</li>
<li>
<a href="${root}config/special/" #if $pane == "Special" then 'class="active"' else ""#>
<a href="$url('config/special')" #if $pane == "Special" then 'class="active"' else ""#>
<span class="glyphicon glyphicon-education"></span>
<strong>$T('cmenu-special')</strong>
</a>
+5 -6
View File
@@ -10,7 +10,7 @@
<h5 class="darkred"><strong>$T('explain-relFolder'):</strong> <span class="path">$defdir</span></h5>
<!--#for $cur, $slot in enumerate($slotinfo)#-->
<!--#set $cansort = $slot.name != '*' and $slot.name != ''#-->
<form action="save" method="post" <!--#if $cansort#-->class="sorting-row"<!--#end if#-->>
<form action="$url('config/categories/save')" method="post" class="fullform <!--#if $cansort then 'sorting-row' else ''#-->">
<table class="catTable">
<!--#if $cur == 0#-->
<tr>
@@ -28,7 +28,6 @@
<span class="glyphicon glyphicon-option-vertical"></span>
</td>
<td>
<input type="hidden" name="apikey" value="$apikey" />
<input type="hidden" name="order" value="$slot.order" />
<input type="hidden" value="$slot.name" name="name" />
<!--#if $slot.name != '*'#-->
@@ -103,12 +102,12 @@
</div>
</div>
</div>
<script type="text/javascript" src="${root}staticcfg/js/jquery-ui.min.js"></script>
<script type="text/javascript" src="$url('staticcfg/js/jquery-ui.min.js', v=$cache_buster)"></script>
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery('.delCat').click(function() {
var theForm = jQuery(this).closest("form");
theForm.attr("action", "delete").submit();
theForm.attr("action", "$url('config/categories/delete')").submit();
});
// Add autocomplete and file-browser
@@ -128,8 +127,8 @@
var data = {}
jQuery(elm).extractFormDataTo(data);
jQuery.ajax({
type: "GET",
url: window.location.pathname + 'save',
type: "POST",
url: "$url('config/categories/save')",
data: data,
async: false // To prevent race-conditions when updating categories
})
@@ -8,10 +8,8 @@
<input type="checkbox" id="advanced-settings-button" name="advanced-settings-button"> $T('button-advanced')
</label>
</div>
<form action="saveDirectories" method="post" name="fullform" class="fullform" autocomplete="off">
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
<form action="$url('config/folders/save')" method="post" class="fullform" autocomplete="off">
<input type="hidden" name="output" value="json" />
<input type="hidden" id="ajax" name="ajax" value="1" />
<div class="section">
<div class="col2">
<h3>$T('userFolders') <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
@@ -35,7 +33,7 @@
<div class="field-pair">
<label class="config" for="complete_dir">$T('opt-complete_dir')</label>
<input type="text" name="complete_dir" id="complete_dir" value="$complete_dir" data-initialdir="$my_home" />
<a class="btn btn-default" href="${root}config/sorting/"><span class="glyphicon glyphicon-sort-by-alphabet"></span> $T('cmenu-sorting')</a>
<a class="btn btn-default" href="$url('config/sorting')"><span class="glyphicon glyphicon-sort-by-alphabet"></span> $T('cmenu-sorting')</a>
<span class="desc">$T('explain-complete_dir') <br/> $T('explain-complete_dir-sorting')</span>
</div>
<div class="field-pair advanced-settings">
@@ -113,7 +111,7 @@
<div class="field-pair">
<label class="config" for="log_dir">$T('opt-log_dir')</label>
<input type="text" name="log_dir" id="log_dir" value="$log_dir" data-initialdir="$my_lcldata" />
<a class="btn btn-default" id="purge_log_files" href="${root}"><span class="glyphicon glyphicon-trash"></span> $T('purge_log_files')</a>
<a class="btn btn-default" id="purge_log_files" href="$url()"><span class="glyphicon glyphicon-trash"></span> $T('purge_log_files')</a>
<span class="desc">$T('explain-log_dir')</span>
</div>
<div class="field-pair">
@@ -139,8 +137,8 @@
if ( confirm("$T('confirm')") ) {
$.ajax({
type: "POST",
url: "../../api",
data: {mode: 'config', name: 'purge_log_files', output: 'json', apikey: jQuery('#apikey').val()}
url: "$url('api')",
data: {mode: 'config', name: 'purge_log_files', output: 'json'}
})
} else {
return false;
+15 -24
View File
@@ -8,9 +8,7 @@
<input type="checkbox" id="advanced-settings-button" name="advanced-settings-button"> $T('button-advanced')
</label>
</div>
<form action="saveGeneral" method="post" name="fullform" class="fullform" autocomplete="off">
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
<input type="hidden" id="ajax" name="ajax" value="1" />
<form action="$url('config/general/save')" method="post" class="fullform" autocomplete="off">
<input type="hidden" name="output" value="json" />
<div class="section">
<div class="col2">
@@ -46,7 +44,6 @@
<!--#end if#-->
<!--#end for#-->
</select>
<span class="desc">$T('explain-web_dir')&nbsp;&nbsp;<a href="$caller_url">$caller_url</a></span>
</div>
<div class="field-pair">
<label class="config" for="language">$T('opt-language')</label>
@@ -223,9 +220,7 @@
</div><!-- /section -->
</form>
<form action="uploadConfig" method="post" name="fullform" class="fullform" autocomplete="off" enctype="multipart/form-data">
<input type="hidden" name="apikey" value="$apikey" />
<input type="hidden" name="ajax" value="1" />
<form action="$url('config/general/upload_config')" method="post" class="fullform" autocomplete="off" enctype="multipart/form-data">
<input type="hidden" name="output" value="json" />
<div class="section">
<div class="col2">
@@ -252,7 +247,7 @@
</form>
</div><!-- /colmask -->
<div class="modal fade" id="modal_qr">
<div class="modal fade" id="modal_qr" tabindex="-1" role="dialog" aria-modal="true" aria-label="$T('explain-qr-code')">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
@@ -280,8 +275,6 @@ jQuery(document).ready(function(){
// Skip the fancy stuff, just submit
this.submit()
})
// No JSON response
jQuery('#ajax').val('')
})
hideOrShowTranslate()
@@ -312,17 +305,16 @@ jQuery(document).ready(function(){
safeCheck.on('change', checkSafety)
// Click functions
jQuery('#apikey, #nzbkey').click(function () { jQuery(this).select() });
jQuery('#apikey_display, #nzbkey').click(function () { jQuery(this).select() });
jQuery('#generate_new_apikey').click(function () {
if (confirm("$T('confirm')")) {
$.ajax({
type: "POST",
url: "../../api",
data: {mode:'config', name:'set_apikey', apikey: jQuery('#apikey').val()},
url: "$url('api')",
data: { mode: 'config', name: 'set_apikey' },
success: function(msg){
jQuery('#apikey').val(msg);
document.location = document.location;
jQuery('#apikey_display').val(msg.apikey);
}
});
}
@@ -331,11 +323,10 @@ jQuery(document).ready(function(){
if (confirm("$T('confirm')")) {
$.ajax({
type: "POST",
url: "../../api",
data: { mode:'config', name:'set_nzbkey', apikey: jQuery('#apikey').val() },
success: function(msg){
jQuery('#nzbkey').val(msg);
document.location = document.location;
url: "$url('api')",
data: { mode: 'config', name: 'set_nzbkey' },
success: function(msg) {
jQuery('#nzbkey').val(msg.nzbkey);
}
});
}
@@ -366,8 +357,8 @@ jQuery(document).ready(function(){
// Submit request and then restart
$.ajax({
type: "POST",
url: "../../api",
data: { mode: 'config', name: 'regenerate_certs', apikey: jQuery('#apikey').val() },
url: "$url('api')",
data: { mode: 'config', name: 'regenerate_certs' },
success: function(msg) {
do_restart()
}
@@ -404,8 +395,8 @@ jQuery(document).ready(function(){
jQuery('#create_backup').click(function () {
$.ajax({
type: "POST",
url: "../../api",
data: {mode:'config', name:'create_backup', output:'json', apikey: jQuery('#apikey').val()},
url: "$url('api')",
data: { mode: 'config', name: 'create_backup', output: 'json' },
success: function(data) {
if(data.value.result) {
alert("$T('backup'):\n" + data.value.message)
+31 -30
View File
@@ -1,4 +1,4 @@
<!--#set global $pane="Email"#-->
<!--#set global $pane="Notify"#-->
<!--#set global $help_uri = $confighelpuri + "notifications"#-->
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
@@ -7,10 +7,11 @@
<!--#def show_notify_checkboxes($section_label)#-->
<!--#for $type in $notify_types#-->
<div class="field-pair">
<label class="config wide" for="${section_label}_prio_$type">
<input type="checkbox" class="notify-checkboxes" name="${section_label}_prio_$type" id="${section_label}_prio_$type" value="1" <!--#if $getVar($section_label + '_prio_' + $type) then 'checked="checked"' else ""#--> />
<label class="config" for="${section_label}_prio_$type">
$T($notify_types[$type]).replace('/', ' / ')
</label>
<input type="checkbox" name="${section_label}_prio_$type" id="${section_label}_prio_$type" value="1" <!--#if $getVar($section_label + '_prio_' + $type) then 'checked="checked"' else ""#--> />
</div>
<!--#end for#-->
<!--#end def#-->
@@ -29,10 +30,8 @@
<!--#end def#-->
<div class="colmask">
<form action="saveNotify" method="post" name="fullform" class="fullform" autocomplete="off">
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
<form action="$url('config/notify/save')" method="post" class="fullform" autocomplete="off">
<input type="hidden" name="output" value="json" />
<input type="hidden" id="ajax" name="ajax" value="1" />
<div class="section" id="email">
<div class="col2">
<h3>$T('cmenu-email') <a href="$help_uri#toc0" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
@@ -93,8 +92,8 @@
</div>
<div class="field-pair no-field-pair-bg">
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
<button class="btn btn-default" type="button" id="test_email" rel="$T('askTestEmail')"><span class="glyphicon glyphicon-envelope"></span> $T('link-testEmail')</button>
<div class="result-box">
<button class="btn btn-default" type="button" id="test_email" rel="$T('askTestEmail')" aria-busy="false"><span class="glyphicon glyphicon-envelope" aria-hidden="true"></span> $T('link-testEmail')</button>
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
<div class="alert"></div>
</div>
</div>
@@ -117,8 +116,8 @@
$show_notify_checkboxes('ncenter')
<div class="field-pair no-field-pair-bg">
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
<button class="btn btn-default" type="button" id="test_notif"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
<div class="result-box">
<button class="btn btn-default" type="button" id="test_notif" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
<div class="alert"></div>
</div>
</div>
@@ -143,8 +142,8 @@
$show_notify_checkboxes('acenter')
<div class="field-pair no-field-pair-bg">
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
<button class="btn btn-default" type="button" id="test_windows"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
<div class="result-box">
<button class="btn btn-default" type="button" id="test_windows" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
<div class="alert"></div>
</div>
</div>
@@ -169,8 +168,8 @@
$show_notify_checkboxes('ntfosd')
<div class="field-pair no-field-pair-bg">
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
<button class="btn btn-default" type="button" id="test_osd"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
<div class="result-box">
<button class="btn btn-default" type="button" id="test_osd" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
<div class="alert"></div>
</div>
</div>
@@ -209,15 +208,15 @@
<label class="config" for="${section_label}_target_${type}">
$T($notify_types[$type]).replace('/', ' / ')
</label>
<input type="checkbox" name="${section_label}_target_${type}_enable" id="${section_label}_target_${type}_enable" value="1" <!--#if $getVar($section_label + '_target_' + $type + '_enable') then 'checked="checked"' else ""#--> />
<input type="checkbox" class="notify-checkboxes" name="${section_label}_target_${type}_enable" id="${section_label}_target_${type}_enable" value="1" <!--#if $getVar($section_label + '_target_' + $type + '_enable') then 'checked="checked"' else ""#--> />
<input type="text" name="${section_label}_target_${type}" id="${section_label}_target_${type}" value="$getVar($section_label + '_target_' + $type)" placeholder="$T('opt-apprise_urls')" />
</div>
<!--#end for#-->
<div class="field-pair no-field-pair-bg">
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
<button class="btn btn-default" type="button" id="test_apprise"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
<div class="result-box">
<button class="btn btn-default" type="button" id="test_apprise" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
<div class="alert"></div>
</div>
</div>
@@ -255,8 +254,8 @@
$show_notify_checkboxes('nscript')
<div class="field-pair no-field-pair-bg">
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
<button class="btn btn-default" type="button" id="test_nscript"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
<div class="result-box">
<button class="btn btn-default" type="button" id="test_nscript" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
<div class="alert"></div>
</div>
</div>
@@ -300,8 +299,8 @@
<!--#end for#-->
<div class="field-pair no-field-pair-bg">
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
<button class="btn btn-default" type="button" id="test_prowl"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
<div class="result-box">
<button class="btn btn-default" type="button" id="test_prowl" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
<div class="alert"></div>
</div>
</div>
@@ -366,8 +365,8 @@
<!--#end for#-->
<div class="field-pair no-field-pair-bg">
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
<button class="btn btn-default" type="button" id="test_pushover"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
<div class="result-box">
<button class="btn btn-default" type="button" id="test_pushover" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
<div class="alert"></div>
</div>
</div>
@@ -403,8 +402,8 @@
$show_notify_checkboxes('pushbullet')
<div class="field-pair no-field-pair-bg">
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
<button class="btn btn-default" type="button" id="test_pushbullet"><span class="glyphicon glyphicon-comment"></span> $T('testNotify')</button>
<div class="result-box">
<button class="btn btn-default" type="button" id="test_pushbullet" aria-busy="false"><span class="glyphicon glyphicon-comment" aria-hidden="true"></span> $T('testNotify')</button>
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
<div class="alert"></div>
</div>
</div>
@@ -445,8 +444,9 @@ jQuery(document).ready(function(){
}
// Disable button and get the data
jQuery(buttonObj).attr("disabled", "disabled")
jQuery(buttonObj).attr("aria-busy", "true")
jQuery(buttonObj).find('span').toggleClass('glyphicon-comment glyphicon-refresh spin-glyphicon')
var data = { mode: buttonObj.id, apikey: '$apikey', output: 'json' };
var data = { mode: buttonObj.id, output: 'json' };
jQuery(buttonObj).parents('.section').extractFormDataTo(data);
// Clear up the box
@@ -454,22 +454,23 @@ jQuery(document).ready(function(){
// Get the request
jQuery.ajax({
type: "GET",
url: "../../api",
type: "POST",
url: "$url('api')",
data: data
}).then(function(data) {
// Remove disabled and make the box
jQuery(buttonObj).removeAttr("disabled")
jQuery(buttonObj).attr("aria-busy", "false")
jQuery(buttonObj).find('span').toggleClass('glyphicon-comment glyphicon-refresh spin-glyphicon')
resultBox.removeClass('alert-success alert-danger').show()
if(data.status) {
resultBox.addClass('alert-success')
resultBox.text('$T('notifications-notesent')')
resultBox.prepend('<span class="glyphicon glyphicon-ok-sign"></span> ')
resultBox.prepend('<span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> ')
} else {
resultBox.addClass('alert-danger')
resultBox.text(data.error)
resultBox.prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ')
resultBox.prepend('<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> ')
}
})
}
+33 -39
View File
@@ -8,8 +8,7 @@
<div class="padTable">
<a class="main-helplink" href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
<p>$T('explain-RSS')</p>
<form action="add_rss_feed" method="post" autocomplete="off">
<input type="hidden" name="apikey" value="$apikey" />
<form data-form="add-rss-feed" action="$url('config/rss/add_rss_feed')" method="post" autocomplete="off">
<table class="catTable addRssTable">
<tr>
<th>&nbsp;</th>
@@ -38,8 +37,7 @@
<!--#if $rss#-->
<div class="section">
<div class="padTable">
<form action="save_rss_feed" method="post" autocomplete="off">
<input type="hidden" name="apikey" value="$apikey" />
<form action="$url('config/rss/save_rss_feed')" method="post" autocomplete="off">
<table id="subscriptions">
<tbody>
<!--#set $feeds = sorted($rss.keys(), key=lambda x: x.lower())#-->
@@ -75,8 +73,7 @@
</form>
<!--#if $feeds#-->
<br/>
<form action="rss_now" method="post" autocomplete="off">
<input type="hidden" name="apikey" value="$apikey" />
<form action="$url('config/rss/rss_now')" method="post" autocomplete="off">
<button type="submit" class="btn btn-default readAll"><span class="glyphicon glyphicon-sort"></span> $T('button-rssNow')</button>
</form>
<!--#end if#-->
@@ -84,8 +81,7 @@
</div>
<!--#end if#-->
<div class="section">
<form action="save_rss_rate" method="post" autocomplete="off">
<input type="hidden" name="apikey" value="$apikey" />
<form action="$url('config/rss/save_rss_rate')" method="post" autocomplete="off">
<div class="col1">
<fieldset>
<div class="field-pair">
@@ -107,7 +103,7 @@
<div class="padTable">
<a class="main-helplink" href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
<h2 class="nomargin activeRSS">
<a href="${root}config/rss/">$T('cmenu-rss')</a> &raquo;
<a href="$url('config/rss')">$T('cmenu-rss')</a> &raquo;
$active_feed
</h2>
<!--#if $error#-->
@@ -116,8 +112,7 @@
$error
</div>
<!--#end if#-->
<form action="upd_rss_feed" method="post">
<input type="hidden" name="apikey" value="$apikey" />
<form action="$url('config/rss/upd_rss_feed')" method="post">
<input type="hidden" name="feed" value="$active_feed" />
<input type="hidden" name="uri" value="$rss[$feed]['uris']" />
<table class="catTable">
@@ -208,8 +203,7 @@
</table>
</form>
<!-- add new filter -->
<form action="upd_rss_filter" method="post">
<input type="hidden" name="apikey" value="$apikey" />
<form data-form="update-rss-filter" action="$url('config/rss/upd_rss_filter')" method="post">
<input type="hidden" name="index" value="$rss[$feed]['filtercount']" />
<input type="hidden" name="feed" value="$active_feed" />
<table class="catTable">
@@ -285,8 +279,7 @@
<!--#set $fnum = 0#-->
<!--#for $filter in $rss[$feed].filters#-->
<!--#set $odd = not $odd#-->
<form action="upd_rss_filter" method="post" autocomplete="off">
<input type="hidden" name="apikey" value="$apikey" />
<form data-form="update-rss-filter" action="$url('config/rss/upd_rss_filter')" method="post" autocomplete="off">
<input type="hidden" name="index" value="$fnum" />
<input type="hidden" name="feed" value="$active_feed" />
<table class="catTable">
@@ -364,8 +357,7 @@
</form>
<!--#set $fnum = $fnum+1#-->
<!--#end for#-->
<form action="download_rss_feed" method="post">
<input type="hidden" name="apikey" value="$apikey" />
<form action="$url('config/rss/download_rss_feed')" method="post">
<input type="hidden" name="feed" value="$active_feed" />
<div class="padding">
<button type="button" class="btn btn-default testFeed" rel="$active_feed"><span class="glyphicon glyphicon-sort"></span> $T('button-preFeed')</button>
@@ -400,9 +392,8 @@
<!--#for $job in $matched#-->
<tr class="infoTableSeperator">
<td>
<form action="download" method="get">
<form data-form="download-rss-job" action="$url('config/rss/download')" method="post">
<input type="hidden" value="$active_feed" name="feed" />
<input type="hidden" name="apikey" value="$apikey" />
<input type="hidden" name="url" value="$job['url']" />
<input type="hidden" name="nzbname" value="$job['nzbname']" />
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span> $T('link-download')</button>
@@ -444,9 +435,8 @@
<!--#for $job in $unmatched#-->
<tr class="infoTableSeperator">
<td>
<form action="download" method="get">
<form data-form="download-rss-job" action="$url('config/rss/download')" method="post">
<input type="hidden" value="$active_feed" name="feed" />
<input type="hidden" name="apikey" value="$apikey" />
<input type="hidden" name="url" value="$job['url']" />
<input type="hidden" name="nzbname" value="$job['nzbname']" />
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span> $T('link-download')</button>
@@ -473,9 +463,8 @@
</div>
<div class="tab-pane padTable" id="rss-tab-done">
<!--#if $downloaded#-->
<form action="clean_rss_jobs" method="post">
<form action="$url('config/rss/clean_rss_jobs')" method="post">
<input type="hidden" value="$active_feed" name="feed" />
<input type="hidden" name="apikey" value="$apikey" />
<table class="catTable">
<thead>
<tr>
@@ -508,7 +497,7 @@
</table>
</form>
<!--#else#-->
$T('none')
$T('none')
<!--#end if#-->
</div>
<!--#end if#-->
@@ -517,12 +506,12 @@
</div>
<!-- /colmask -->
<form method="post" action="save_rss_feed" class="modal fade" id="rss_edit_modal">
<form method="post" action="$url('config/rss/save_rss_feed')" class="modal fade" id="rss_edit_modal" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="rss-edit-modal-title">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">$T('Edit') <span id="feed_edit_name_label"></span></h4>
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="rss-edit-modal-title">$T('Edit') <span id="feed_edit_name_label"></span></h4>
</div>
<div class="modal-body">
<div class="form-group">
@@ -535,7 +524,6 @@
<span class="help-block">$T('addMultipleFeeds')</span>
</div>
<input type="hidden" name="feed" id="feed_edit_old_name" />
<input type="hidden" name="apikey" value="$apikey" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> $T('cancel')</button>
@@ -545,7 +533,7 @@
</div><!-- /.modal-dialog -->
</form><!-- /.modal -->
<script type="text/javascript" src="${root}staticcfg/js/jquery.tablesort.min.js"></script>
<script type="text/javascript" src="$url('staticcfg/js/jquery.tablesort.min.js', v=$cache_buster)"></script>
<script type="text/javascript">
function urlencode(str) {
return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
@@ -589,8 +577,8 @@ jQuery(document).ready(function(){
var whichFeed = jQuery(this).attr("rel");
jQuery.ajax({
type: "POST",
url: "del_rss_feed",
data: {feed: whichFeed, apikey: "$apikey" }
url: "$url('config/rss/del_rss_feed')",
data: {feed: whichFeed }
}).done(function( msg ) {
// Let us leave!
formWasSubmitted = true;
@@ -604,8 +592,8 @@ jQuery(document).ready(function(){
var whichFeed = jQuery(this).attr("rel");
jQuery.ajax({
type: "POST",
url: "toggle_rss_feed",
data: {feed: whichFeed, apikey: "$apikey" }
url: "$url('config/rss/toggle_rss_feed')",
data: {feed: whichFeed }
}).done(function() {
// Let us leave!
formWasSubmitted = true;
@@ -615,7 +603,7 @@ jQuery(document).ready(function(){
});
// Only the Accept filter needs all the options
jQuery('form[action="upd_rss_filter"]').find('select[name="filter_type"]').change(function() {
jQuery('form[data-form="update-rss-filter"]').find('select[name="filter_type"]').change(function() {
jQuery(this).parent().parent().find('select:not([name="filter_type"])').attr('disabled', jQuery(this).val() !== "A" && jQuery(this).val() !== "S")
})
// Trigger on-load for all
@@ -644,8 +632,8 @@ jQuery(document).ready(function(){
var whichFeed = jQuery(this).attr("rel");
jQuery.ajax({
type: "POST",
url: "test_rss_feed",
data: {feed: whichFeed, apikey: "$apikey" }
url: "$url('config/rss/test_rss_feed')",
data: {feed: whichFeed }
}).done(function( msg ) {
// Let us leave!
formWasSubmitted = true;
@@ -657,15 +645,21 @@ jQuery(document).ready(function(){
jQuery('.cleanFeed').click(function(){
setActiveIcon(this)
var theForm = jQuery(this).closest("form");
theForm.attr("action", "clean_rss_jobs").submit();
theForm.attr("action", "$url('config/rss/clean_rss_jobs')").submit();
});
jQuery('.evalFeed').click(function(){
setActiveIcon(this)
var theForm = jQuery(this).closest("form");
theForm.attr("action", "$url('config/rss/eval_rss_feed')").submit();
});
jQuery('.delFilter').click(function(){
var theForm = jQuery(this).closest("form");
theForm.attr("action", "del_rss_filter").submit();
theForm.attr("action", "$url('config/rss/del_rss_filter')").submit();
});
jQuery('form[action="download"]').ajaxForm({
jQuery('form[data-form="download-rss-job"]').ajaxForm({
datatype: 'json',
beforeSubmit: function (_, form) {
jQuery(form).find('button').attr("disabled", "disabled")
@@ -17,17 +17,16 @@ else:
<div class="col2">
<h3>$T('addSchedule') <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
</div><!-- /col2 -->
<form action="addSchedule" method="post" autocomplete="off">
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
<form data-form="add-schedule" action="$url('config/scheduling/add_schedule')" method="post" autocomplete="off">
<div class="col1">
<fieldset>
<div class="field-pair">
<label class="config" for="hour">$T('hour').capitalize() : $T('minute').capitalize()</label>
<select name="hour" id="hour">
<select name="hour" id="hour" aria-label="$T('hour').capitalize()">
<!--#for $i in range(24)#-->
<option value="$i" <!--#if hour == i then 'selected="selected"' else ""#--> > $str($i).zfill(2) </option>
<!--#end for#-->
</select>&nbsp;<b>:</b>&nbsp;<select name="minute" id="minute">
</select>&nbsp;<b>:</b>&nbsp;<select name="minute" id="minute" aria-label="$T('minute').capitalize()">
<!--#for $i in range(60)#-->
<option value="$i"> $str($i).zfill(2) </option>
<!--#end for#-->
@@ -90,13 +89,12 @@ else:
<!--#set $odd = True#-->
<!--#for $schednum, $line in enumerate($schedlines)#-->
<!--#set $odd = not $odd#-->
<form action="delSchedule" method="post">
<input type="hidden" name="apikey" value="$apikey"/>
<input type="hidden" name="line" id="line" value="$line"/>
<form data-form="del-schedule" action="$url('config/scheduling/del_schedule')" method="post">
<input type="hidden" name="line" value="$line"/>
<div class="field-pair infoTableSeperator <!--#if $odd then "" else " alt"#-->">
<input type="checkbox" name="schedenabled" value="$line" <!--#if int($taskinfo[$schednum][5]) > 0 then 'checked="checked"' else ""#-->>
<button class="btn btn-default float-left"><span class="glyphicon glyphicon-trash"></span></button>
<div class="scheduleEntry">
<input type="checkbox" name="schedenabled" value="$line" aria-label="$T('enabled')" aria-describedby="schedule-description-$schednum" <!--#if int($taskinfo[$schednum][5]) > 0 then 'checked="checked"' else ""#-->>
<button class="btn btn-default float-left" type="submit" aria-label="$T('nzo-delete')" aria-describedby="schedule-description-$schednum"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button>
<div class="scheduleEntry" id="schedule-description-$schednum">
<span class="time">$taskinfo[$schednum][1]:$taskinfo[$schednum][2]</span><span class="frequency">$taskinfo[$schednum][3]</span> <span class="darkred">$taskinfo[$schednum][4]</span>
</div>
</div>
@@ -136,8 +134,8 @@ else:
jQuery('[name="schedenabled"]').click(function() {
jQuery.ajax({
type: "POST",
url: "toggleSchedule",
data: {line: jQuery(this).val(), apikey: "$apikey" }
url: "$url('config/scheduling/toggle_schedule')",
data: {line: jQuery(this).val() }
}).done(function() {
// Let us leave!
formWasSubmitted = true;
+48 -25
View File
@@ -40,8 +40,7 @@
<h3>$T('addServer') <a href="$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
</div>
<div class="col1">
<form action="addServer" method="post" autocomplete="off" onsubmit="removeObfuscation();">
<input type="hidden" name="apikey" value="$apikey" />
<form data-form="add-server" action="$url('config/server/add_server')" method="post" autocomplete="off">
<input type="hidden" name="output" value="json" />
<fieldset>
<div class="field-pair">
@@ -138,8 +137,8 @@
</div>
<div class="field-pair no-field-pair-bg">
<button class="btn btn-default addNewServer" disabled data-toggle="tooltip" data-placement="top" title="$T('wizard-test-server-required')"><span class="glyphicon glyphicon-plus"></span> $T('button-addServer')</button>
<button class="btn btn-default testServer" type="button"><span class="glyphicon glyphicon-sort"></span> $T('button-testServer')</button>
<div class="result-box">
<button class="btn btn-default testServer" type="button" aria-busy="false"><span class="glyphicon glyphicon-sort" aria-hidden="true"></span> $T('button-testServer')</button>
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
<div class="alert"></div>
</div>
</div>
@@ -153,11 +152,9 @@
<!--#set $cur_prio_color = -1 #-->
<!--#set $last_prio = -1 #-->
<!--#for $cur, $server in enumerate($servers) #-->
<form action="saveServer" method="post" class="fullform" autocomplete="off">
<input type="hidden" name="apikey" value="$apikey" />
<form action="$url('config/server/save_server')" method="post" class="fullform" autocomplete="off">
<input type="hidden" name="output" value="json" />
<input type="hidden" name="server" value="$server['name']" />
<input type="hidden" name="ajax" value=1 />
<div class="section <!--#if int($server['enable']) == 0 then 'server-disabled' else ""#-->">
<div class="col2 <!--#if int($server['enable']) == 0 then 'server-disabled' else ""#-->">
@@ -276,10 +273,10 @@
</div>
<div class="field-pair no-field-pair-bg">
<button class="btn btn-default saveButton"><span class="glyphicon glyphicon-ok"></span> $T('button-saveChanges')</button>
<button class="btn btn-default testServer" type="button"><span class="glyphicon glyphicon-sort"></span> $T('button-testServer')</button>
<button class="btn btn-default testServer" type="button" aria-busy="false"><span class="glyphicon glyphicon-sort" aria-hidden="true"></span> $T('button-testServer')</button>
<button class="btn btn-default delServer"><span class="glyphicon glyphicon-trash"></span> $T('button-delServer')</button>
<div class="result-box">
<div class="result-box" role="status" aria-live="polite" aria-atomic="true">
<div class="alert"></div>
</div>
</div>
@@ -328,8 +325,8 @@
<!--#end for#-->
</div>
<script type="text/javascript" src="${root}staticcfg/js/chartist.min.js"></script>
<script type="text/javascript" src="${root}staticcfg/js/filesize.min.js"></script>
<script type="text/javascript" src="$url('staticcfg/js/chartist.min.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('staticcfg/js/filesize.min.js', v=$cache_buster)"></script>
<script type="text/javascript">
// Standardize chart options
var chartOptions = {
@@ -480,11 +477,9 @@
// Initialize tooltips
jQuery('[data-toggle="tooltip"]').tooltip()
// Reload form in case we change items that make the servers appear different
// Reload the page after saving in case we change items that make the servers appear different
jQuery('input[name="priority"], input[name="displayname"], textarea[name="notes"]').on('change', function(event) {
var parentForm = jQuery(event.target).parents("form")
parentForm.unbind("submit")
parentForm.find('input[name="ajax"]').val('')
jQuery(event.target).parents("form").attr("data-reload-on-save", "")
})
/**
@@ -549,28 +544,31 @@
var theButton = jQuery(this)
var resultBox = theButton.parents('.col1').find('.result-box .alert');
theButton.attr("disabled", "disabled")
theButton.attr("aria-busy", "true")
theButton.find('span').toggleClass('glyphicon-sort glyphicon-refresh spin-glyphicon')
resultBox.removeClass('alert-success alert-danger').addClass('alert-info').html("$T('srv-testing')").show()
jQuery.ajax({
type: "POST",
url: "../../api",
url: "$url('api')",
data: "mode=config&name=test_server&" + jQuery(this).parents('form:first').serialize()
}).then(function(data) {
// Let's replace the link
msg = data.value.message.replace('https://sabnzbd.org/certificate-errors', '<a href="https://sabnzbd.org/certificate-errors" class="alert-link" target="_blank">https://sabnzbd.org/certificate-errors</a>')
msg = msg.replace('-', '<br>')
// Fill the box and enable the button
resultBox.removeClass('alert-success alert-danger').show()
resultBox.removeClass('alert-info alert-success alert-danger').show()
resultBox.html(msg)
theButton.removeAttr("disabled")
theButton.attr("aria-busy", "false")
theButton.find('span').toggleClass('glyphicon-sort glyphicon-refresh spin-glyphicon')
// Success or not?
if(data.value.result) {
resultBox.addClass('alert-success')
resultBox.prepend('<span class="glyphicon glyphicon-ok-sign"></span> ')
resultBox.prepend('<span class="glyphicon glyphicon-ok-sign" aria-hidden="true"></span> ')
// Allow adding the new server if we are in the new-server section
if(theButton.parents("form[action='addServer']").length) {
if(theButton.parents("form[data-form='add-server']").length) {
jQuery(".addNewServer").removeAttr("disabled")
jQuery(".addNewServer").removeAttr("data-toggle")
jQuery(".addNewServer").removeAttr("title")
@@ -578,10 +576,10 @@
}
} else {
resultBox.addClass('alert-danger')
resultBox.prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ')
resultBox.prepend('<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> ')
// Disable the adding of new server, just to be sure
if(theButton.parents("form[action='addServer']").length) {
if(theButton.parents("form[data-form='add-server']").length) {
jQuery(".addNewServer").attr("disabled", "disabled")
jQuery(".addNewServer").attr("data-toggle", "tooltip")
jQuery(".addNewServer").attr("data-placement", "top")
@@ -592,9 +590,34 @@
});
});
jQuery('.addNewServer').click(function(event){
event.preventDefault()
removeObfuscation()
var theButton = jQuery(this)
var resultBox = theButton.parents('.col1').find('.result-box .alert')
theButton.attr("disabled", "disabled")
jQuery.ajax({
type: "POST",
url: "$url('config/server/add_server')",
data: theButton.parents('form:first').serialize()
}).then(function(data) {
if(data.status) {
// Success — reload to show the new server
formWasSubmitted = true
formHasChanged = false
location.reload()
} else {
// Show error in the result box
resultBox.removeClass('alert-success').addClass('alert-danger').show()
resultBox.html('<span class="glyphicon glyphicon-exclamation-sign"></span> ' + data.error)
theButton.removeAttr("disabled")
}
})
})
jQuery('.delServer').click(function(){
if( confirm("$T('confirm')") ) {
jQuery(this).parents('form:first').attr('action','delServer').submit();
jQuery(this).parents('form:first').attr('action',"$url('config/server/delete_server')").submit();
// Let us leave!
formWasSubmitted = true;
formHasChanged = false;
@@ -605,7 +628,7 @@
jQuery('.clrServer').click(function(){
if( confirm("$T('confirm')") ) {
jQuery(this).parents('form:first').attr('action','clrServer').submit();
jQuery(this).parents('form:first').attr('action',"$url('config/server/clear_server')").submit();
// Let us leave!
formWasSubmitted = true;
formHasChanged = false;
@@ -618,8 +641,8 @@
var whichServer = jQuery(this).attr("name");
jQuery.ajax({
type: "POST",
url: "toggleServer",
data: {server: whichServer, apikey: "$apikey" }
url: "$url('config/server/toggle_server')",
data: {server: whichServer }
}).done(function() {
// Let us leave!
formWasSubmitted = true;
+10 -14
View File
@@ -20,8 +20,7 @@
<!--#set $selected_types = ["0"] if not len($selected_types) else $selected_types #-->
<!-- SORTER $cur -->
<div class="section <!--#if $cur != 0#-->sorter<!--#end if#-->" id="sorter_$cur" <!--#if $cur == 0#-->style="display: none;"<!--#end if#-->>
<form action="save_sorter" method="post" autocomplete="off" <!--#if $cur != 0#-->class="sorting-row"<!--#end if#-->>
<input type="hidden" name="apikey" value="$apikey" />
<form action="$url('config/sorting/save_sorter')" method="post" autocomplete="off" <!--#if $cur != 0#-->class="sorting-row"<!--#end if#-->>
<input type="hidden" name="order" value="$slot.order" />
<input type="hidden" value="$slot.name" name="name" />
<!--#if $cur == 0#-->
@@ -347,8 +346,7 @@
<div class="section align-center sorting-quick-setup">
<h3>$T('sort-quick-add'):</h3>
<!--#if "tv" in $categories#-->
<form action="save_sorter" method="post" autocomplete="off">
<input type="hidden" name="apikey" value="$apikey" />
<form action="$url('config/sorting/save_sorter')" method="post" autocomplete="off">
<input type="hidden" name="order" value="0" />
<input type="hidden" name="is_active" value="1" />
<input type="hidden" name="name" value="">
@@ -366,8 +364,7 @@
</form>
<!--#end if#-->
<!--#if "movies" in $categories#-->
<form action="save_sorter" method="post" autocomplete="off">
<input type="hidden" name="apikey" value="$apikey" />
<form action="$url('config/sorting/save_sorter')" method="post" autocomplete="off">
<input type="hidden" name="order" value="0" />
<input type="hidden" name="is_active" value="1" />
<input type="hidden" name="name" value="">
@@ -388,7 +385,7 @@
</div>
<!--#end if#-->
</div>
<script type="text/javascript" src="${root}staticcfg/js/jquery-ui.min.js"></script>
<script type="text/javascript" src="$url('staticcfg/js/jquery-ui.min.js', v=$cache_buster)"></script>
<script type="text/javascript">
// http://stackoverflow.com/questions/2219924/
var typewatch = (function(){
@@ -414,13 +411,12 @@
typewatch(function () {
jQuery.ajax({
type: "GET",
url: "../../api",
url: "$url('api')",
data: {
mode: 'eval_sort',
job_name: jQuery('#preview_name_' + sort_nr).val(),
sort_string: preview_sort_string,
multipart_label: jQuery('#multipart_label_' + sort_nr).val(),
apikey: '$apikey',
output: 'json'
},
success: function(data) {
@@ -437,7 +433,7 @@
jQuery(document).ready(function() {
jQuery('.delSorter').click(function() {
var theForm = jQuery(this).closest("form");
theForm.attr("action", "delete").submit();
theForm.attr("action", "$url('config/sorting/delete')").submit();
});
jQuery('.addSorter').click(function(){
@@ -494,8 +490,8 @@
var data = {}
jQuery(elm).extractFormDataTo(data);
jQuery.ajax({
type: "GET",
url: window.location.pathname + 'save_sorter',
type: "POST",
url: "$url('config/sorting/save_sorter')",
data: data,
async: false // To prevent race-conditions when updating sorters
})
@@ -509,8 +505,8 @@
var whichSorter = jQuery(this).attr("rel");
jQuery.ajax({
type: "POST",
url: "toggle_sorter",
data: {sorter: whichSorter, apikey: "$apikey" }
url: "$url('config/sorting/toggle_sorter')",
data: {sorter: whichSorter }
}).done(function() {
formWasSubmitted = true;
formHasChanged = false;
@@ -3,8 +3,7 @@
<!--#include $webdir + "/_inc_header_uc.tmpl"#-->
<div class="colmask">
<form action="saveSpecial" method="post" autocomplete="off">
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
<form action="$url('config/special/save')" method="post" class="fullform" autocomplete="off">
<div class="padTable">
<h4 class="darkred nomargin">$T('explain-special')</h4>
</div>
@@ -8,9 +8,7 @@
<input type="checkbox" id="advanced-settings-button" name="advanced-settings-button"> $T('button-advanced')
</label>
</div>
<form action="saveSwitches" method="post" name="fullform" class="fullform" autocomplete="off">
<input type="hidden" id="apikey" name="apikey" value="$apikey" />
<input type="hidden" id="ajax" name="ajax" value="1" />
<form action="$url('config/switches/save')" method="post" class="fullform" autocomplete="off">
<input type="hidden" name="output" value="json" />
<div class="section advanced-settings">
<div class="col2">
@@ -152,6 +150,7 @@
<select name="auto_sort" id="auto_sort">
<option value="">$T('default')</option>
<option value="remaining asc" <!--#if $auto_sort == "remaining asc" then 'selected="selected"' else ""#--> >$T('Glitter-sortRemaining')</option>
<option value="remaining_bytes asc" <!--#if $auto_sort == "remaining_bytes asc" then 'selected="selected"' else ""#--> >$T('Glitter-sortRemainingBytesAsc')</option>
<option value="avg_age desc" <!--#if $auto_sort == "avg_age desc" then 'selected="selected"' else ""#--> >$T('Glitter-sortAgeAsc')</option>
<option value="avg_age asc" <!--#if $auto_sort == "avg_age asc" then 'selected="selected"' else ""#--> >$T('Glitter-sortAgeDesc')</option>
<option value="name asc" <!--#if $auto_sort == "name asc" then 'selected="selected"' else ""#--> >$T('Glitter-sortNameAsc')</option>
@@ -261,7 +260,7 @@
<div class="field-pair">
<label class="config" for="history_retention_option">$T('opt-history_retention')</label>
<select name="history_retention_option" id="history_retention_option">
<option value="all" <!--#if $auto_sort == "all" then 'selected="selected"' else ""#-->>$T('history_retention-all')</option>
<option value="all" <!--#if $history_retention_option == "all" then 'selected="selected"' else ""#-->>$T('history_retention-all')</option>
<option value="number-archive" <!--#if $history_retention_option == "number-archive" then 'selected="selected"' else ""#-->>$T('history_retention-number-archive')</option>
<option value="number-delete" <!--#if $history_retention_option == "number-delete" then 'selected="selected"' else ""#-->>$T('history_retention-number-delete')</option>
<option value="days-archive" <!--#if $history_retention_option == "days-archive" then 'selected="selected"' else ""#-->>$T('history_retention-days-archive')</option>
@@ -394,9 +393,9 @@ jQuery(document).ready(function() {
// Send request
jQuery.ajax({
type: "GET",
url: "../../api",
data: "mode=set_config_default&apikey=${apikey}&output=json&keyword=" + key_container.join('&keyword=')
type: "POST",
url: "$url('api')",
data: "mode=set_config_default&output=json&keyword=" + key_container.join('&keyword=')
}).then(function(data) {
// Reload page
document.location = document.location
+17 -21
View File
@@ -1,5 +1,5 @@
<!DOCTYPE HTML>
<html lang="$active_lang">
<html lang="$active_lang" data-color-scheme="$color_scheme">
<head>
<title>SABnzbd - $T('login')</title>
@@ -7,38 +7,34 @@
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, maximum-scale=1" />
<meta name="apple-mobile-web-app-title" content="SABnzbd" />
<link rel="apple-touch-icon" sizes="76x76" href="../staticcfg/ico/apple-touch-icon-76x76-precomposed.png" />
<link rel="apple-touch-icon" sizes="120x120" href="../staticcfg/ico/apple-touch-icon-120x120-precomposed.png" />
<link rel="apple-touch-icon" sizes="152x152" href="../staticcfg/ico/apple-touch-icon-152x152-precomposed.png" />
<link rel="apple-touch-icon" sizes="180x180" href="../staticcfg/ico/apple-touch-icon-180x180-precomposed.png" />
<link rel="apple-touch-icon" sizes="192x192" href="../staticcfg/ico/android-192x192.png" />
<link rel="shortcut icon" href="../staticcfg/ico/favicon.ico?v=$cache_buster" />
<link rel="apple-touch-icon" sizes="76x76" href="$url('staticcfg/ico/apple-touch-icon-76x76-precomposed.png', v=$cache_buster)" />
<link rel="apple-touch-icon" sizes="120x120" href="$url('staticcfg/ico/apple-touch-icon-120x120-precomposed.png', v=$cache_buster)" />
<link rel="apple-touch-icon" sizes="152x152" href="$url('staticcfg/ico/apple-touch-icon-152x152-precomposed.png', v=$cache_buster)" />
<link rel="apple-touch-icon" sizes="180x180" href="$url('staticcfg/ico/apple-touch-icon-180x180-precomposed.png', v=$cache_buster)" />
<link rel="apple-touch-icon" sizes="192x192" href="$url('staticcfg/ico/android-192x192.png', v=$cache_buster)" />
<link rel="shortcut icon" href="$url('staticcfg/ico/favicon.ico', v=$cache_buster)" />
<link rel="stylesheet" type="text/css" href="../staticcfg/bootstrap/css/bootstrap.min.css?v=$cache_buster" />
<link rel="stylesheet" type="text/css" href="../staticcfg/css/login.css?v=$cache_buster" />
<!--#if $color_scheme not in ('Light', '') #-->
<link rel="stylesheet" type="text/css" href="../staticcfg/css/${color_scheme}.css?v=$cache_buster"/>
<!--#end if#-->
<link rel="stylesheet" type="text/css" href="$url('staticcfg/bootstrap/css/bootstrap.min.css', v=$cache_buster)" />
<link rel="stylesheet" type="text/css" href="$url('staticcfg/css/login.css', v=$cache_buster)" />
<script type="text/javascript" src="../staticcfg/js/jquery-3.5.1.min.js?v=$cache_buster"></script>
<script type="text/javascript" src="../staticcfg/bootstrap/js/bootstrap.min.js?v=$cache_buster"></script>
<script type="text/javascript" src="$url('staticcfg/js/jquery-3.7.1.min.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('staticcfg/bootstrap/js/bootstrap.min.js', v=$cache_buster)"></script>
</head>
<html>
<body>
<div class="account-wall">
<div class="text-center logo-header">
<!--#include $webdir + "/staticcfg/images/logo-full.svg"#-->
<a href="https://sabnzbd.org/wiki/faq#why-login" target="_blank">
<span class="glyphicon glyphicon-question-sign"></span>
<a href="https://sabnzbd.org/wiki/faq#why-login" target="_blank" aria-label="$T('menu-help')">
<span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span>
</a>
</div>
<form class="form-signin" action="./" method="post">
<form class="form-signin" action="./login" method="post">
<!--#if $error#-->
<div class="alert alert-danger" role="alert">$error</div>
<!--#end if#-->
<input type="text" class="form-control" name="username" placeholder="$T('srv-username')" autocomplete="username" required autofocus>
<input type="password" class="form-control" name="password" placeholder="$T('srv-password')" autocomplete="current-password" required>
<input type="text" class="form-control" name="username" placeholder="$T('srv-username')" aria-label="$T('srv-username')" autocomplete="username" required autofocus>
<input type="password" class="form-control" name="password" placeholder="$T('srv-password')" aria-label="$T('srv-password')" autocomplete="current-password" required>
<button class="btn btn-default"><span class="glyphicon glyphicon-circle-arrow-right"></span> $T('login') </button>
@@ -63,4 +59,4 @@
} catch(err) { }
</script>
</body>
</html>
</html>
@@ -1 +0,0 @@
@import url('Night.css') screen and (prefers-color-scheme: dark);
@@ -1,311 +0,0 @@
/*
* Night theme — overrides :root color tokens defined in style.css.
* Only structural/behavioural rules that can't be expressed as color tokens remain below.
*/
:root {
--clr-page-bg: black;
--clr-surface: #303030;
--clr-surface-alt: #444444;
--clr-surface-hover: #666666;
--clr-border: #555555;
--clr-border-subtle: #252525;
--clr-text: #EBEBEB;
--clr-text-muted: #c7c7c7;
--clr-error: #ff3333;
--clr-link: #63a7e1;
--clr-input-bg: #555555;
--clr-input-border: #252525;
--clr-dropdown-bg: #444444;
--clr-modal-bg: #727272;
--clr-modal-header-bg: #3C3C3C;
--clr-table-bg: #555555;
--clr-table-row-alt: #444444;
--clr-toggle-inactive: #666666;
}
/* Links use a custom colour in dark mode */
a:not(.btn) {
color: var(--clr-link);
}
/* Buttons get a subtle white shadow in dark mode for depth */
.btn {
box-shadow: 1px 1px 1px rgba(255, 255, 255, .1);
}
/* Borders on interactive controls */
.btn:not(.btn-danger),
.btn-default,
input,
select,
textarea,
.advanced-button,
.list-group-item {
border-color: var(--clr-input-border) !important;
}
.advanced-button {
background-color: var(--clr-surface-alt);
}
/* Sidebar section header */
.col2 h3 {
background: none repeat scroll 0 0 var(--clr-surface-alt);
}
/* Various elements that need the alt surface */
.catTable,
.dropdown-menu .divider,
.Key tr:nth-child(odd),
.language:hover,
.navbar-default .navbar-nav>.open>a,
.navbar-default .navbar-nav>.open>a:focus,
.navbar-default .navbar-nav>.open>a:hover,
.navbar-default .navbar-nav>li>a.active,
.navbar-default .navbar-nav>li>a:hover,
.navbar-default .navbar-nav>li>a:focus,
.navbar-logo:hover,
.quoteBlock,
.server-disabled,
#serverResponse,
.table>tbody>tr:nth-child(odd),
.table-striped>tbody>tr:nth-child(odd),
ul.tabs li.active a,
select[disabled],
select:hover {
background-color: var(--clr-surface-alt) !important;
color: var(--clr-text) !important;
}
/* Button hovers */
.btn:not(.btn-danger):hover,
.btn:not(.btn-danger):active:focus {
background-color: var(--clr-surface-hover);
}
.btn:not(.btn-danger):active {
color: var(--clr-text);
}
/* Error / failed colour */
.failed {
color: var(--clr-error) !important;
}
/* Secondary text */
#rightGreyText,
small {
color: var(--clr-text-muted) !important;
}
/* Controls and form elements using input bg */
.advanced-buttonSeperator,
.alt,
.infoTableSeperator.alt,
.btn:not(.btn-danger),
.btn-default.disabled:active,
.btn-default.disabled:focus,
.btn-default.disabled:hover,
a.btn.btn-default,
select.form-control,
.form-control[disabled],
.input-group-addon,
#inner,
.navbar-default,
.search-box input,
.select,
.table-striped>tbody>tr:nth-child(even),
.table>tbody>tr:nth-child(even),
.tab-pane tr:nth-child(odd),
textarea,
ul.tabs a.active,
a.list-group-item,
.dropdown-menu>li>a,
input[type="text"],
input[type="email"],
input[type="url"],
input[type="date"],
input[type="number"],
input[type="password"],
input[disabled],
select {
background-color: var(--clr-input-bg);
color: var(--clr-text);
}
.Categories form.sorting-row:nth-child(2n-1) tr {
background-color: var(--clr-surface);
}
/* Focus / active border */
.btn-default:focus,
.form-control:focus,
input:focus,
textarea:focus,
select:focus {
border-color: #707070 !important;
outline: initial !important;
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
}
/* Modal backdrop */
.modal-backdrop {
background-color: #262626 !important;
}
/* Table structural */
.Key tr,
.Config .table {
border: none;
}
.table>tbody>tr>td,
.table>tbody>tr>th,
.infoTableSeperator,
.data-row {
border-top: none;
}
.modal-footer {
border-top: 1px solid rgb(131 131 131);
}
hr {
border-top: 1px solid var(--clr-border);
}
/* Danger button dark border */
.btn-danger {
border-color: #7b2b28;
}
/* Section borders */
.tab-content .catTable tbody,
ul.tabs a,
.section,
#addFeed,
#addFeedContent,
#subscriptions,
.RSS form[action="add_rss_feed"] tr:nth-child(even) {
border: 1px solid var(--clr-border);
}
/* Hover states */
.Categories form:first-of-type tr:last-of-type,
.default,
.dropdown-menu>li>a:focus,
.dropdown-menu>li>a:hover {
background-color: var(--clr-surface-hover);
}
/* Elements using primary text colour */
.activeRSS,
.activeRSS a,
.activeRSS a:visited,
.btn-default,
.checkbox label,
.feed-row td,
.help-block,
#content,
.navbar-default .navbar-nav>li>a,
.navbar-default .navbar-nav>li>a>.glyphicon,
.path,
.Servers .ct-label,
.time,
.main-restarting.in,
#search-dropdown .dropdown-header,
ul.tabs a,
a.wizard-advanced-settings,
.quoteBlock a,
a.main-helplink,
.col2 h3 a,
.text-center a,
.text-center a:hover {
color: var(--clr-text);
}
/* Remove backgrounds on container/content wrappers */
.container,
#content {
background-color: unset !important;
}
/* Server chart lines */
.Servers .ct-series-a .ct-line,
.Servers .ct-series-a .ct-point {
stroke: var(--clr-text);
}
/* Sections/cards use dark surface */
#inner,
.section,
#addFeed,
#addFeedContent {
background-color: var(--clr-surface);
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
/* Active tab uses card surface */
.nav.nav-tabs li a {
color: var(--clr-text);
}
.nav.nav-tabs li a:hover {
background-color: var(--clr-surface-alt);
border-color: var(--clr-border);
border-bottom: none;
}
.nav.nav-tabs li.active a,
.nav.nav-tabs li.active a:hover {
border-color: var(--clr-border);
border-bottom: none;
background-color: var(--clr-surface);
color: var(--clr-text);
}
/* QR modal needs light background */
#modal_qr .modal-body {
background-color: #EBEBEB;
}
/* RSS icon */
.rss-icon-svg {
fill: white;
}
.rss-symbol {
fill: var(--clr-input-bg);
}
/* Placeholder */
::placeholder {
color: var(--clr-text) !important;
opacity: 0.5;
}
/* Tooltip — inverted (light tooltip on dark page) */
.tooltip-inner {
background-color: #E4E4E4 !important;
color: #000 !important;
}
.tooltip.bottom .tooltip-arrow {
border-bottom-color: #E4E4E4 !important;
}
.tooltip.top .tooltip-arrow {
border-top-color: #E4E4E4 !important;
}
.tooltip.left .tooltip-arrow {
border-left-color: #E4E4E4 !important;
}
.tooltip.right .tooltip-arrow {
border-right-color: #E4E4E4 !important;
}
.Special .glyphicon-asterisk {
color: #E4E4E4 !important;
}
@@ -1,19 +1,32 @@
:root {
/* Light mode defaults — overridden by Night.css */
--clr-page-bg: #E4E4E4;
--clr-surface: #FFFFFF;
--clr-input-bg: #FFFFFF;
--clr-border: rgba(0, 0, 0, 0.15);
--clr-text: #000000;
--clr-text-muted: #636363;
/* Follow the OS by default (Auto); forced by data-color-scheme below */
color-scheme: light dark;
/* Color palette — light-dark(light value, dark value) */
--clr-page-bg: light-dark(#E4E4E4, black);
--clr-surface: light-dark(#FFFFFF, #303030);
--clr-input-bg: light-dark(#FFFFFF, #555555);
--clr-border: light-dark(rgba(0, 0, 0, 0.15), #555555);
--clr-text: light-dark(#000000, #EBEBEB);
--clr-text-muted: light-dark(#636363, #c7c7c7);
--radius-lg: 8px;
--clr-toggle-active: #f9ca33;
--clr-toggle-inactive: #aaaaaa;
--clr-toggle-inactive: light-dark(#aaaaaa, #666666);
}
/* The server renders the configured scheme into this attribute; empty/unknown = Auto */
html[data-color-scheme="light" i] {
color-scheme: light;
}
html[data-color-scheme="night" i] {
color-scheme: dark;
}
body {
overflow-y: scroll;
background-color: var(--clr-page-bg);
color: var(--clr-text);
}
.logo-header {
@@ -58,10 +71,23 @@ body {
margin-top: 5px
}
.form-signin input,
.form-signin .btn {
background-color: var(--clr-input-bg);
color: var(--clr-text);
border-color: light-dark(#ccc, #252525);
}
.form-signin .btn {
width: 100%;
margin-top: 10px;
font-weight: bold;
box-shadow: 1px 1px 1px light-dark(transparent, rgba(255, 255, 255, .1));
}
::placeholder {
color: var(--clr-text) !important;
opacity: 0.5;
}
.btn .glyphicon {
@@ -111,3 +137,69 @@ input[type="checkbox"]:focus-visible {
outline-offset: 2px;
border-radius: 10px;
}
/***
Dark-mode structural rules
Colors live in the light-dark() tokens above; these are the rules that cannot
be expressed as a color value. The two blocks below MUST stay identical:
the first applies when Night is forced, the second when the OS is dark and Light is not forced.
***/
html[data-color-scheme="night" i] {
/* Focus / active border */
.form-signin input:focus,
.form-signin .btn:focus {
border-color: #707070 !important;
outline: initial !important;
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
}
.text-center a,
.text-center a:hover {
color: var(--clr-text);
}
/* Tooltip — inverted (light tooltip on dark page) */
.tooltip-inner {
background-color: #E4E4E4 !important;
color: #000 !important;
}
.tooltip.bottom .tooltip-arrow {
border-bottom-color: #E4E4E4 !important;
}
.tooltip.top .tooltip-arrow {
border-top-color: #E4E4E4 !important;
}
}
@media (prefers-color-scheme: dark) {
html:not([data-color-scheme="light" i]) {
/* Focus / active border */
.form-signin input:focus,
.form-signin .btn:focus {
border-color: #707070 !important;
outline: initial !important;
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
}
.text-center a,
.text-center a:hover {
color: var(--clr-text);
}
/* Tooltip — inverted (light tooltip on dark page) */
.tooltip-inner {
background-color: #E4E4E4 !important;
color: #000 !important;
}
.tooltip.bottom .tooltip-arrow {
border-bottom-color: #E4E4E4 !important;
}
.tooltip.top .tooltip-arrow {
border-top-color: #E4E4E4 !important;
}
}
}
@@ -1,29 +1,40 @@
:root {
/* Follow the OS by default (Auto); forced by data-color-scheme below */
color-scheme: light dark;
/* Border radius scale */
--radius-sm: 4px; /* dropdowns */
--radius-md: 4px; /* inputs, buttons, section headers */
--radius-lg: 6px; /* cards, modals */
/* Color palette — light mode defaults; override in Night.css */
--clr-page-bg: #E4E4E4; /* body/page background */
--clr-surface: #FFFFFF; /* cards/sections (.section, #addFeed, etc.) */
--clr-surface-alt: #F8F8F8; /* alternating rows, .alt elements */
--clr-surface-hover: #f6f6f6; /* hovered rows and buttons */
--clr-border: #dfdede; /* card/section borders */
--clr-border-subtle: #E5E5E5; /* inner dividers (#subscriptions, data-row) */
--clr-text: #000000; /* primary body text */
--clr-text-muted: #666666; /* secondary text (.col2 p, .feed-row td) */
--clr-error: red; /* errors, failed items */
--clr-link: inherit; /* links (Bootstrap default in light) */
--clr-input-bg: #FFFFFF; /* form inputs, buttons */
--clr-input-border: #d4d0c8; /* input borders */
--clr-toggle-active: #f9ca33; /* accent color (toggles, focus rings) */
--clr-toggle-inactive: #aaaaaa; /* toggle track when off */
--clr-dropdown-bg: #FFFFFF; /* dropdown menus */
--clr-modal-bg: #FFFFFF; /* modal body/footer */
--clr-modal-header-bg: #3C3C3C; /* modal header (dark in both themes) */
--clr-table-bg: #FFFFFF; /* table background */
--clr-table-row-alt: #F8F8F8; /* alternating table row background */
/* Color palette — light-dark(light value, dark value) */
--clr-page-bg: light-dark(#E4E4E4, black); /* body/page background */
--clr-surface: light-dark(#FFFFFF, #303030); /* cards/sections (.section, #addFeed, etc.) */
--clr-surface-alt: light-dark(#F8F8F8, #444444); /* alternating rows, .alt elements */
--clr-surface-hover: light-dark(#f6f6f6, #666666); /* hovered rows and buttons */
--clr-border: light-dark(#dfdede, #555555); /* card/section borders */
--clr-border-subtle: light-dark(#E5E5E5, #252525); /* inner dividers (#subscriptions, data-row) */
--clr-text: light-dark(#000000, #EBEBEB); /* primary body text */
--clr-text-muted: light-dark(#666666, #c7c7c7); /* secondary text (.col2 p, .feed-row td) */
--clr-error: light-dark(red, #ff3333); /* errors, failed items */
--clr-input-bg: light-dark(#FFFFFF, #555555); /* form inputs, buttons */
--clr-input-border: light-dark(#d4d0c8, #252525); /* input borders */
--clr-toggle-active: #f9ca33; /* accent color (toggles, focus rings) */
--clr-toggle-inactive: light-dark(#aaaaaa, #666666); /* toggle track when off */
--clr-dropdown-bg: light-dark(#FFFFFF, #444444); /* dropdown menus */
--clr-modal-bg: light-dark(#FFFFFF, #727272); /* modal body/footer */
--clr-modal-header-bg: #3C3C3C; /* modal header (dark in both themes) */
--clr-table-bg: light-dark(#FFFFFF, #555555); /* table background */
--clr-table-row-alt: light-dark(#F8F8F8, #444444); /* alternating table row background */
}
/* The server renders the configured scheme into this attribute; empty/unknown = Auto */
html[data-color-scheme="light" i] {
color-scheme: light;
}
html[data-color-scheme="night" i] {
color-scheme: dark;
}
body {
@@ -31,6 +42,18 @@ body {
background-color: var(--clr-page-bg);
color: var(--clr-text);
}
/* Bootstrap's `a:focus { outline: 5px auto -webkit-focus-ring-color }` renders as a
heavy dark ring once color-scheme is declared. Replace it with a subtle themed
outline shown only for keyboard focus, matching the toggle-switch focus style. */
a:focus {
outline: none;
}
a:focus-visible {
outline: 2px solid var(--clr-toggle-active);
outline-offset: 2px;
}
#logo {
display: block;
margin: 3px auto auto;
@@ -253,7 +276,21 @@ input[type="checkbox"]+.desc {
margin: 0;
padding: 0 12px 0 6px;
}
textarea, select, input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="email"], input[type="month"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="time"], input[type="url"], input[type="week"] {
textarea,
select,
input[type="date"],
input[type="datetime"],
input[type="datetime-local"],
input[type="email"],
input[type="month"],
input[type="number"],
input[type="password"],
input[type="search"],
input[type="tel"],
input[type="text"],
input[type="time"],
input[type="url"],
input[type="week"] {
padding-left: 5px;
border: 1px solid #d4d0c8;
}
@@ -488,7 +525,7 @@ tr.separator {
.RSS .catTable select {
max-width: 120px;
}
.RSS form[action="add_rss_feed"] tr:nth-child(even) {
.RSS form[data-form="add-rss-feed"] tr:nth-child(even) {
border: 1px solid #E5E5E5;
}
.RSS .tab-pane table th:not(.no-sort) {
@@ -689,6 +726,10 @@ input:has(+ .clearBtn) {
#filebrowser_modal .list-group-item {
font-weight: bold;
}
#filebrowser_modal a.list-group-item:hover,
#filebrowser_modal a.list-group-item:focus {
background-color: var(--clr-surface-hover);
}
#filebrowser_modal .list-group-item span {
margin-right: 10px;
top: 0;
@@ -994,12 +1035,12 @@ input[type="checkbox"] {
max-width: 150px !important;
}
.Scheduling form[action="addSchedule"] input[type="checkbox"] {
.Scheduling form[data-form="add-schedule"] input[type="checkbox"] {
margin-top: 0px;
margin-left: -20px;
}
.Scheduling form[action="delSchedule"] input[type="checkbox"] {
.Scheduling form[data-form="del-schedule"] input[type="checkbox"] {
position: initial;
float: left;
margin: 9px 10px 0px 5px;
@@ -1058,18 +1099,7 @@ input[type="checkbox"] {
height: 40px;
width: 40px;
}
/*
.navbar-logo-wide {
display: none;
}
.navbar-logo-wide {
padding-top: 9px;
}
.navbar-logo-wide svg {
height: 36px;
width: 130px;
}
*/
.navbar-default .navbar-nav>li>a {
color: black;
outline: none;
@@ -1136,7 +1166,7 @@ input[type="checkbox"] {
}
.Servers .col2 .label {
margin-top: 8px;
margin-top: 12px;
font-size: 0.85em;
float: right;
line-height: 1.1em;
@@ -1207,8 +1237,8 @@ input[type="checkbox"] {
}
.Servers .col2 label,
.Email .col2 label {
margin: 2px 0 0 4px;
.Notify .col2 label {
margin: 6px 0 0 6px;
cursor: pointer;
}
@@ -1253,6 +1283,11 @@ input[type="checkbox"] {
top: 1px;
}
.Notify .notify-checkboxes {
float: left;
margin-right: 8px;
}
.main-restarting.in {
text-align: center;
opacity: 0.9;
@@ -1394,7 +1429,7 @@ html[dir="rtl"] .checkbox-days {
float: none;
}
html[dir="rtl"] .Scheduling form[action="addSchedule"] input[type="checkbox"] {
html[dir="rtl"] .Scheduling form[data-form="add-schedule"] input[type="checkbox"] {
right: 5px;
}
@@ -1592,3 +1627,591 @@ html[dir="rtl"] .Scheduling form[action="addSchedule"] input[type="checkbox"] {
padding-right: 5px;
}
}
/***
Dark-mode structural rules
Colors live in the light-dark() tokens above; these are the rules that cannot
be expressed as a color value. The two blocks below MUST stay identical:
the first applies when Night is forced, the second when the OS is dark and Light is not forced.
***/
html[data-color-scheme="night" i] {
/* Links use a custom colour in dark mode */
a:not(.btn) {
color: #63a7e1;
}
/* Buttons get a subtle white shadow in dark mode for depth */
.btn {
box-shadow: 1px 1px 1px rgba(255, 255, 255, .1);
}
/* Borders on interactive controls */
.btn:not(.btn-danger),
.btn-default,
input,
select,
textarea,
.advanced-button,
.list-group-item {
border-color: var(--clr-input-border) !important;
}
.advanced-button {
background-color: var(--clr-surface-alt);
}
/* Sidebar section header */
.col2 h3 {
background: none repeat scroll 0 0 var(--clr-surface-alt);
}
/* Various elements that need the alt surface */
.catTable,
.dropdown-menu .divider,
.Key tr:nth-child(odd),
.language:hover,
.navbar-default .navbar-nav>.open>a,
.navbar-default .navbar-nav>.open>a:focus,
.navbar-default .navbar-nav>.open>a:hover,
.navbar-default .navbar-nav>li>a.active,
.navbar-default .navbar-nav>li>a:hover,
.navbar-default .navbar-nav>li>a:focus,
.navbar-logo:hover,
.quoteBlock,
.server-disabled,
#serverResponse,
.table>tbody>tr:nth-child(odd),
.table-striped>tbody>tr:nth-child(odd),
ul.tabs li.active a,
select[disabled],
select:hover {
background-color: var(--clr-surface-alt) !important;
color: var(--clr-text) !important;
}
/* Button hovers */
.btn:not(.btn-danger):hover,
.btn:not(.btn-danger):active:focus {
background-color: var(--clr-surface-hover);
}
.btn:not(.btn-danger):active {
color: var(--clr-text);
}
/* Error / failed colour */
.failed {
color: var(--clr-error) !important;
}
/* Secondary text */
#rightGreyText,
small {
color: var(--clr-text-muted) !important;
}
/* Controls and form elements using input bg */
.advanced-buttonSeperator,
.alt,
.infoTableSeperator.alt,
.btn:not(.btn-danger),
.btn-default.disabled:active,
.btn-default.disabled:focus,
.btn-default.disabled:hover,
a.btn.btn-default,
select.form-control,
.form-control[disabled],
.input-group-addon,
#inner,
.navbar-default,
.search-box input,
.select,
.table-striped>tbody>tr:nth-child(even),
.table>tbody>tr:nth-child(even),
.tab-pane tr:nth-child(odd),
textarea,
ul.tabs a.active,
a.list-group-item,
.dropdown-menu>li>a,
input[type="text"],
input[type="email"],
input[type="url"],
input[type="date"],
input[type="number"],
input[type="password"],
input[disabled],
select {
background-color: var(--clr-input-bg);
color: var(--clr-text);
}
.Categories form.sorting-row:nth-child(2n-1) tr {
background-color: var(--clr-surface);
}
/* Focus / active border */
.btn-default:focus,
.form-control:focus,
input:focus,
textarea:focus,
select:focus {
border-color: #707070 !important;
outline: initial !important;
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
}
/* Modal backdrop */
.modal-backdrop {
background-color: #262626 !important;
}
/* Table structural */
.Key tr,
.Config .table {
border: none;
}
.table>tbody>tr>td,
.table>tbody>tr>th,
.infoTableSeperator,
.data-row {
border-top: none;
}
.modal-footer {
border-top: 1px solid rgb(131 131 131);
}
hr {
border-top: 1px solid var(--clr-border);
}
/* Danger button dark border */
.btn-danger {
border-color: #7b2b28;
}
/* Section borders */
.tab-content .catTable tbody,
ul.tabs a,
.section,
#addFeed,
#addFeedContent,
#subscriptions,
.RSS form[data-form="add-rss-feed"] tr:nth-child(even),
.Config .table {
border: 1px solid var(--clr-border);
}
/* Hover states */
.Categories form:first-of-type tr:last-of-type,
.default,
.dropdown-menu>li>a:focus,
.dropdown-menu>li>a:hover {
background-color: var(--clr-surface-hover);
}
/* Elements using primary text colour */
.activeRSS,
.activeRSS a,
.activeRSS a:visited,
.btn-default,
.checkbox label,
.feed-row td,
.help-block,
#content,
.navbar-default .navbar-nav>li>a,
.navbar-default .navbar-nav>li>a>.glyphicon,
.path,
.Servers .ct-label,
.time,
.main-restarting.in,
#search-dropdown .dropdown-header,
ul.tabs a,
a.wizard-advanced-settings,
.quoteBlock a,
a.main-helplink,
.col2 h3 a,
.text-center a,
.text-center a:hover {
color: var(--clr-text);
}
/* Remove backgrounds on container/content wrappers */
.container,
#content {
background-color: unset !important;
}
/* Server chart lines */
.Servers .ct-series-a .ct-line,
.Servers .ct-series-a .ct-point {
stroke: var(--clr-text);
}
/* Sections/cards use dark surface */
#inner,
.section,
#addFeed,
#addFeedContent {
background-color: var(--clr-surface);
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
/* Active tab uses card surface */
.nav.nav-tabs li a {
color: var(--clr-text);
}
.nav.nav-tabs li a:hover {
background-color: var(--clr-surface-alt);
border-color: var(--clr-border);
border-bottom: none;
}
.nav.nav-tabs li.active a,
.nav.nav-tabs li.active a:hover {
border-color: var(--clr-border);
border-bottom: none;
background-color: var(--clr-surface);
color: var(--clr-text);
}
/* QR modal needs light background */
#modal_qr .modal-body {
background-color: #EBEBEB;
}
/* RSS icon */
.rss-icon-svg {
fill: white;
}
.rss-symbol {
fill: var(--clr-input-bg);
}
/* Placeholder */
::placeholder {
color: var(--clr-text) !important;
opacity: 0.5;
}
/* Tooltip — inverted (light tooltip on dark page) */
.tooltip-inner {
background-color: #E4E4E4 !important;
color: #000 !important;
}
.tooltip.bottom .tooltip-arrow {
border-bottom-color: #E4E4E4 !important;
}
.tooltip.top .tooltip-arrow {
border-top-color: #E4E4E4 !important;
}
.tooltip.left .tooltip-arrow {
border-left-color: #E4E4E4 !important;
}
.tooltip.right .tooltip-arrow {
border-right-color: #E4E4E4 !important;
}
.Special .glyphicon-asterisk {
color: #E4E4E4 !important;
}
}
@media (prefers-color-scheme: dark) {
html:not([data-color-scheme="light" i]) {
/* Links use a custom colour in dark mode */
a:not(.btn) {
color: #63a7e1;
}
/* Buttons get a subtle white shadow in dark mode for depth */
.btn {
box-shadow: 1px 1px 1px rgba(255, 255, 255, .1);
}
/* Borders on interactive controls */
.btn:not(.btn-danger),
.btn-default,
input,
select,
textarea,
.advanced-button,
.list-group-item {
border-color: var(--clr-input-border) !important;
}
.advanced-button {
background-color: var(--clr-surface-alt);
}
/* Sidebar section header */
.col2 h3 {
background: none repeat scroll 0 0 var(--clr-surface-alt);
}
/* Various elements that need the alt surface */
.catTable,
.dropdown-menu .divider,
.Key tr:nth-child(odd),
.language:hover,
.navbar-default .navbar-nav>.open>a,
.navbar-default .navbar-nav>.open>a:focus,
.navbar-default .navbar-nav>.open>a:hover,
.navbar-default .navbar-nav>li>a.active,
.navbar-default .navbar-nav>li>a:hover,
.navbar-default .navbar-nav>li>a:focus,
.navbar-logo:hover,
.quoteBlock,
.server-disabled,
#serverResponse,
.table>tbody>tr:nth-child(odd),
.table-striped>tbody>tr:nth-child(odd),
ul.tabs li.active a,
select[disabled],
select:hover {
background-color: var(--clr-surface-alt) !important;
color: var(--clr-text) !important;
}
/* Button hovers */
.btn:not(.btn-danger):hover,
.btn:not(.btn-danger):active:focus {
background-color: var(--clr-surface-hover);
}
.btn:not(.btn-danger):active {
color: var(--clr-text);
}
/* Error / failed colour */
.failed {
color: var(--clr-error) !important;
}
/* Secondary text */
#rightGreyText,
small {
color: var(--clr-text-muted) !important;
}
/* Controls and form elements using input bg */
.advanced-buttonSeperator,
.alt,
.infoTableSeperator.alt,
.btn:not(.btn-danger),
.btn-default.disabled:active,
.btn-default.disabled:focus,
.btn-default.disabled:hover,
a.btn.btn-default,
select.form-control,
.form-control[disabled],
.input-group-addon,
#inner,
.navbar-default,
.search-box input,
.select,
.table-striped>tbody>tr:nth-child(even),
.table>tbody>tr:nth-child(even),
.tab-pane tr:nth-child(odd),
textarea,
ul.tabs a.active,
a.list-group-item,
.dropdown-menu>li>a,
input[type="text"],
input[type="email"],
input[type="url"],
input[type="date"],
input[type="number"],
input[type="password"],
input[disabled],
select {
background-color: var(--clr-input-bg);
color: var(--clr-text);
}
.Categories form.sorting-row:nth-child(2n-1) tr {
background-color: var(--clr-surface);
}
/* Focus / active border */
.btn-default:focus,
.form-control:focus,
input:focus,
textarea:focus,
select:focus {
border-color: #707070 !important;
outline: initial !important;
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
}
/* Modal backdrop */
.modal-backdrop {
background-color: #262626 !important;
}
/* Table structural */
.Key tr,
.Config .table {
border: none;
}
.table>tbody>tr>td,
.table>tbody>tr>th,
.infoTableSeperator,
.data-row {
border-top: none;
}
.modal-footer {
border-top: 1px solid rgb(131 131 131);
}
hr {
border-top: 1px solid var(--clr-border);
}
/* Danger button dark border */
.btn-danger {
border-color: #7b2b28;
}
/* Section borders */
.tab-content .catTable tbody,
ul.tabs a,
.section,
#addFeed,
#addFeedContent,
#subscriptions,
.RSS form[data-form="add-rss-feed"] tr:nth-child(even),
.Config .table {
border: 1px solid var(--clr-border);
}
/* Hover states */
.Categories form:first-of-type tr:last-of-type,
.default,
.dropdown-menu>li>a:focus,
.dropdown-menu>li>a:hover {
background-color: var(--clr-surface-hover);
}
/* Elements using primary text colour */
.activeRSS,
.activeRSS a,
.activeRSS a:visited,
.btn-default,
.checkbox label,
.feed-row td,
.help-block,
#content,
.navbar-default .navbar-nav>li>a,
.navbar-default .navbar-nav>li>a>.glyphicon,
.path,
.Servers .ct-label,
.time,
.main-restarting.in,
#search-dropdown .dropdown-header,
ul.tabs a,
a.wizard-advanced-settings,
.quoteBlock a,
a.main-helplink,
.col2 h3 a,
.text-center a,
.text-center a:hover {
color: var(--clr-text);
}
/* Remove backgrounds on container/content wrappers */
.container,
#content {
background-color: unset !important;
}
/* Server chart lines */
.Servers .ct-series-a .ct-line,
.Servers .ct-series-a .ct-point {
stroke: var(--clr-text);
}
/* Sections/cards use dark surface */
#inner,
.section,
#addFeed,
#addFeedContent {
background-color: var(--clr-surface);
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
/* Active tab uses card surface */
.nav.nav-tabs li a {
color: var(--clr-text);
}
.nav.nav-tabs li a:hover {
background-color: var(--clr-surface-alt);
border-color: var(--clr-border);
border-bottom: none;
}
.nav.nav-tabs li.active a,
.nav.nav-tabs li.active a:hover {
border-color: var(--clr-border);
border-bottom: none;
background-color: var(--clr-surface);
color: var(--clr-text);
}
/* QR modal needs light background */
#modal_qr .modal-body {
background-color: #EBEBEB;
}
/* RSS icon */
.rss-icon-svg {
fill: white;
}
.rss-symbol {
fill: var(--clr-input-bg);
}
/* Placeholder */
::placeholder {
color: var(--clr-text) !important;
opacity: 0.5;
}
/* Tooltip — inverted (light tooltip on dark page) */
.tooltip-inner {
background-color: #E4E4E4 !important;
color: #000 !important;
}
.tooltip.bottom .tooltip-arrow {
border-bottom-color: #E4E4E4 !important;
}
.tooltip.top .tooltip-arrow {
border-top-color: #E4E4E4 !important;
}
.tooltip.left .tooltip-arrow {
border-left-color: #E4E4E4 !important;
}
.tooltip.right .tooltip-arrow {
border-right-color: #E4E4E4 !important;
}
.Special .glyphicon-asterisk {
color: #E4E4E4 !important;
}
}
}
File diff suppressed because one or more lines are too long.
File diff suppressed because one or more lines are too long.
File diff suppressed because one or more lines are too long.
@@ -243,6 +243,11 @@ $.fn.extractFormDataTo = function(target) {
*
* (c) 2015 SABnzbd Team, Inc. All rights reserved.
*/
$.ajaxSetup({
headers: { "X-SABnzbd-CSRF": csrfToken }
});
function config_success() {
$('.saveButton[disabled=disabled]').each(function () {
$(this).removeAttr("disabled").html('<span class="glyphicon glyphicon-ok"></span> '+configTranslate.saveChanges);
@@ -291,7 +296,7 @@ function do_restart() {
$('.main-restarting .restarting-url').text(urlTotal)
// Initiate restart
$.ajax({ url: '../../api?mode=restart&apikey=' + sabSession,
$.ajax({ url: rootURL + 'api?mode=restart', type: 'POST',
complete: function() {
// Keep counter of failures
var loopCounter = 0;
@@ -371,6 +376,8 @@ jQuery.extend(jQuery.fn.typeahead.defaults, {
})
$(document).ready(function () {
$('form').append('<input type="hidden" name="csrf_token" value="' + csrfToken + '">');
/**
Restart function
**/
@@ -403,7 +410,7 @@ $(document).ready(function () {
$(this).attr("disabled", "disabled").removeClass('btn-danger').html('<span class="glyphicon glyphicon-transfer"></span> ' + configTranslate.saving);
});
},
success: function (json) {
success: function (json, statusText, xhr, form) {
if (json.error) {
$('#config_err_msg').text(json.error);
alert(json.error)
@@ -417,6 +424,12 @@ $(document).ready(function () {
$('#config_err_msg').text(" ");
setTimeout(config_success, 1000);
}
} else if(form && form.is('[data-reload-on-save]')) {
// Values changed that are rendered by the server, so reload the page
$('#config_err_msg').text(" ");
formWasSubmitted = true;
formHasChanged = false;
location.reload();
} else {
$('#config_err_msg').text(" ");
setTimeout(config_success, 1000);
@@ -509,7 +522,7 @@ $(document).ready(function() {
// Load things to search if we haven't yet
if(!pagesContainer[0]) {
$.each(arrPages, function(index, page) {
$.get(rootURL + 'config/' + page + '/', function(data) {
$.get(rootURL + 'config/' + page, function(data) {
pagesContainer[index] = $(data).find('label')
});
});
@@ -638,7 +651,7 @@ function doConfigSearch(value) {
searchOutput.append($('<li class="divider"></li>'))
searchOutput.append($('<li class="dropdown-header"></li>').text(configTranslate.searchPages[page_index]))
$.each(subResults, function(index, result) {
var resultUrl = rootURL + 'config/' + arrPages[page_index] + '/#' + $(result).attr('for')
var resultUrl = rootURL + 'config/' + arrPages[page_index] + '#' + $(result).attr('for')
searchOutput.append(
$('<li></li>').append(
$('<a class="config-search-result"></a>')
@@ -1,21 +1,21 @@
<div class="history" id="history-tab">
<div class="history-header">
<h2>$T('menu-history') <small data-bind="visible: history.showArchive()">($T('archive'))</small></h2>
<a href="#" data-bind="click: history.showMultiEdit, visible: hasHistory()">
<a href="#" aria-label="$T('Glitter-multiOperations')" data-bind="click: history.showMultiEdit, visible: hasHistory()">
<span class="glyphicon glyphicon-tasks" data-tooltip="true" data-placement="left" title="$T('Glitter-multiOperations')"></span>
</a>
</div>
<table class="table table-hover history-table paginated">
<table class="table table-hover history-table paginated" aria-label="$T('menu-history')">
<thead>
<tr>
<th style="width: 25px;"></th>
<th></th>
<th class="table-status-header" data-bind="css: { 'table-header-status-smaller' : extraHistoryColumns().length || displayCompact() }"></th>
<th scope="col" style="width: 25px;"><span class="sr-only">$T('Glitter-result')</span></th>
<th scope="col"><span class="sr-only">$T('name')</span></th>
<th class="table-status-header" scope="col" data-bind="css: { 'table-header-status-smaller' : extraHistoryColumns().length || displayCompact() }"><span class="sr-only">$T('status')</span></th>
<!-- ko foreach: extraHistoryColumns -->
<th class="table-header-extra"></th>
<th class="table-header-extra" scope="col"><span class="sr-only" data-bind="text: glitterTranslate.column[\$data]"></span></th>
<!-- /ko -->
<th style="width: 130px;"></th>
<th style="width: 60px;"></th>
<th scope="col" style="width: 130px;"><span class="sr-only">$T('post-Completed')</span></th>
<th scope="col" style="width: 60px;"><span class="sr-only">$T('Glitter-actions')</span></th>
</tr>
</thead>
<!-- ko if: !hasHistory() -->
@@ -30,10 +30,10 @@
<tbody data-bind="foreach: history.historyItems, visible: hasHistory()" style="display: none;">
<tr class="history-item" data-bind="css: {'history-failed-download':failed()}">
<td>
<div data-bind="visible: processingWaiting()">
<span class="glyphicon glyphicon-time"></span>
<div role="img" aria-label="$T('post-Queued')" data-bind="visible: processingWaiting()">
<span class="glyphicon glyphicon-time" aria-hidden="true"></span>
</div>
<div data-bind="visible: processingDownload()">
<div role="img" aria-label="$T('stage-download')" data-bind="visible: processingDownload()">
<div class="processing-download">
<div class="loader-bar-one"></div>
<div class="loader-bar-two"></div>
@@ -41,17 +41,17 @@
<div class="loader-bar-four"></div>
</div>
</div>
<div data-bind="visible: (!failed() && !processingDownload() && !processingWaiting())">
<span class="glyphicon glyphicon-ok"></span>
<div role="img" aria-label="$T('post-Completed')" data-bind="visible: (!failed() && !processingDownload() && !processingWaiting())">
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
</div>
<div data-bind="visible: failed() && canRetry()">
<a class="retry-button" href="#" data-bind="click: retry">
<span class="glyphicon glyphicon-exclamation-sign"></span>
<a class="retry-button" href="#" aria-label="$T('button-retry')" data-bind="click: retry">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
</a>
</div>
<div data-bind="visible: failed() && !canRetry()">
<span class="retry-button-inactive">
<span class="glyphicon glyphicon-exclamation-sign"></span>
<span class="retry-button-inactive" role="img" aria-label="$T('post-Failed')">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
</span>
</div>
</td>
@@ -70,10 +70,10 @@
<td class="history-completedon row-wrap-text" data-bind="text: completedOn(), attr: { 'data-timestamp': completed }" onclick="showDetails(this)"></td>
<td class="delete">
<label data-bind="visible: parent.isMultiEditing()">
<input type="checkbox" name="multiedit" title="$T('Glitter-multiSelect')" data-bind="click: parent.addMultiEdit, attr: { 'id': 'multiedit_' + id } " />
<input type="checkbox" name="multiedit" title="$T('Glitter-multiSelect')" aria-label="$T('Glitter-selectJob')" data-bind="click: parent.addMultiEdit, attr: { 'id': 'multiedit_' + id } " />
</label>
<div class="dropdown" data-bind="visible: !parent.isMultiEditing()">
<a href="#" data-toggle="dropdown" data-bind="click: updateAllHistoryInfo">
<a href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="$T('nzoDetails')" data-bind="click: updateAllHistoryInfo">
<span class="caret"></span>
</a>
<!-- ko if: hasDropdown() -->
@@ -95,7 +95,6 @@
<div class="col-sm-2">$T('status')</div>
<div class="col-sm-10">
<span data-bind="text: glitterTranslate.status[historyStatus.status()] ? glitterTranslate.status[historyStatus.status()] : statusText()"></span>
<a href="#" class="mark-completed-link" data-bind="visible: failed(), click: markAsCompleted" title="$T('button-mark-completed')"><span class="glyphicon glyphicon-ok"></span> $T('post-Completed')</a>
</div>
</div>
<div class="row">
@@ -120,11 +119,14 @@
<div class="col-sm-10 history-status-modallink" data-bind="longText: actions, longTextType: name()"></div>
</div>
<!-- /ko -->
<div class="col-sm-12 text-right" data-bind="visible: failed()">
<a href="#" class="btn btn-default mark-completed-btn" data-bind="click: markAsCompleted"><span class="glyphicon glyphicon-ok"></span> $T('button-mark-completed')</a>
</div>
</div>
</div>
<!-- /ko -->
</div>
<a href="#" data-bind="click: parent.triggerRemoveDownload">
<a href="#" data-bind="click: parent.triggerRemoveDownload, attr: { 'aria-label': processingDownload() == 2 ? '$T('abort')' : '$T('nzo-delete')' }">
<span class="hover-button glyphicon glyphicon-trash" data-bind="css: { 'glyphicon-stop' : processingDownload() == 2, disabled : processingDownload() == 1 }, attr: { title: processingDownload() == 2 ? '$T('abort')' : '$T('nzo-delete')' }"></span>
</a>
</td>
@@ -135,15 +137,20 @@
<div class="history-footer">
<div class="input-group search-box">
<input type="text" class="form-control" placeholder="$T('Glitter-search')" required data-bind="textInput: history.searchTerm, event: { keydown: history.clearSearchTerm }" />
<a data-bind="event: { mousedown: history.clearSearchTerm }">
<input type="text" class="form-control" placeholder="$T('Glitter-search')" aria-label="$T('Glitter-search')" required data-bind="textInput: history.searchTerm, event: { keydown: history.clearSearchTerm }" />
<a href="#" data-tooltip="true" data-html="true" data-placement="right" title="$T('Glitter-searchExplain')" data-bind="click: history.clearSearchTerm, attr: { 'aria-label': history.searchTerm() ? '$T('Glitter-clearSearch')' : '$T('Glitter-search')' }">
<span class="glyphicon" data-bind="css: { 'glyphicon-search' : !history.searchTerm(), 'glyphicon-remove' : history.searchTerm() }"></span>
</a>
</div>
<ul class="pagination" data-bind="foreach: history.pagination.allpages(), visible: history.pagination.hasPagination" style="display: none;">
<li data-bind="css: { active: isCurrent, disabled: isDots }, click: onclick">
<span data-bind="text: page"></span>
<li data-bind="css: { active: isCurrent, disabled: isDots }">
<!-- ko ifnot: isDots -->
<a href="#" data-bind="text: page, click: onclick, attr: { 'aria-current': isCurrent ? 'page' : null }"></a>
<!-- /ko -->
<!-- ko if: isDots -->
<span aria-hidden="true" data-bind="text: page"></span>
<!-- /ko -->
</li>
</ul>
+21 -7
View File
@@ -5,7 +5,7 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-logo" href="./" aria-label="SABnzbd $T('menu-queue')">
<a class="navbar-logo" href="$url()" aria-label="SABnzbd $T('menu-queue')">
#include $webdir + "/../../Config/templates/staticcfg/images/logo-small.svg"#
</a>
<div class="btn-group">
@@ -48,7 +48,7 @@
</a>
<div class="dropdown-menu max-speed-input">
<div data-bind="visible: !bandwithLimit()">
<a href="./config/general/#bandwidth_max_value">
<a href="$url('config/general#bandwidth_max_value')">
<span class="glyphicon glyphicon-cog"></span> $T('Glitter-setMaxLinespeed')
</a>
</div>
@@ -68,7 +68,7 @@
</li>
<!--#if $have_rss_defined#-->
<li data-tooltip="true" data-placement="bottom" title="$T('cmenu-rss')">
<a href="./config/rss/" aria-label="$T('cmenu-rss')">
<a href="$url('config/rss')" aria-label="$T('cmenu-rss')">
<svg class="rss-icon-svg" viewBox="0 0 8 8">
<rect class="rss-button" width="8" height="8" />
<circle class="rss-symbol" cx="2" cy="6" r="1" />
@@ -79,7 +79,7 @@
</li>
<!--#end if#-->
<li data-tooltip="true" data-placement="bottom" title="SABnzbd $T('menu-config')">
<a href="./config/" aria-label="SABnzbd $T('menu-config')"><span class="glyphicon glyphicon-cog"></span></a>
<a href="$url('config')" aria-label="SABnzbd $T('menu-config')"><span class="glyphicon glyphicon-cog"></span></a>
</li>
<li class="dropdown main-menu-link" data-bind="css: { 'active-on-queue-finish-menu': finishaction()}">
<a href="#" data-toggle="dropdown" onclick="keepOpen(this)" aria-label="$T('Glitter-mainMenu')" aria-haspopup="true" aria-expanded="false">
@@ -91,14 +91,28 @@
<li><a href="#modal-help" data-toggle="modal"><span class="glyphicon glyphicon-question-sign"></span> $T('menu-help')</a></li>
<li><a href="https://sabnzbd.org/donate" target="_blank"><span class="glyphicon glyphicon-heart"></span> $T('menu-donate')</a></li>
<!--#if $have_logout or $have_quota or $have_rss_defined or $have_watched_dir or $pp_pause_event#--><li class="divider"></li><!--#end if#-->
<!--#if $have_logout#--><li><a href="./login/?logout=1"><span class="glyphicon glyphicon-log-out"></span> $T('logout')</a></li><!--#end if#-->
<!--#if $have_logout#--><li>
<form method="post" action="$url('logout')">
<input type="hidden" name="csrf_token" value="$csrf_token" />
<button type="submit"><span class="glyphicon glyphicon-log-out"></span> $T('logout')</button>
</form>
</li><!--#end if#-->
<!--#if $have_quota#--><li><a href="#" data-bind="click: doQueueAction" data-mode="reset_quota">$T('link-resetQuota')</a></li><!--#end if#-->
<!--#if $have_rss_defined#--><li><a href="#" data-bind="click: doQueueAction" data-mode="rss_now">$T('button-rssNow')</a></li><!--#end if#-->
<!--#if $have_watched_dir#--><li><a href="#" data-bind="click: doQueueAction" data-mode="watched_now">$T('sch-scan_folder')</a></li><!--#end if#-->
<!--#if $pp_pause_event#--><li><a href="#" data-bind="click: doQueueAction" data-mode="resume_pp">$T('sch-resume_post')</a></li><!--#end if#-->
<li class="divider"></li>
<li><a href="./shutdown/?apikey=$apikey&amp;pid=$pid" data-bind="click: shutdownSAB">$T('shutdownSab')</a></li>
<li><a href="#" data-bind="click: restartSAB">$T('Glitter-restartSab')</a></li>
<li>
<form method="post" action="$url('shutdown')" data-bind="submit: shutdownSAB">
<input type="hidden" name="csrf_token" value="$csrf_token" />
<button type="submit">$T('shutdownSab')</button>
</form>
</li>
<li>
<form data-bind="submit: restartSAB">
<button type="submit">$T('Glitter-restartSab')</button>
</form>
</li>
<li class="divider"></li>
<li class="dropdown-header"><span class="glyphicon glyphicon-off"></span> $T('Glitter-onFinish'):</li>
<li>
@@ -1,8 +1,8 @@
<div id="queue-messages" class="queue-messages" data-bind="visible: hasMessages() || displayTabbed()" style="display: none;">
<table class="table table-hover table-messages">
<table class="table table-hover table-messages" aria-label="$T('warnings')">
<thead>
<tr>
<th class="table-messages-header-label"></th>
<th class="table-messages-header-label"><span class="sr-only">$T('warnings')</span></th>
<th style="width: 30px;"></th>
</tr>
</thead>
@@ -11,7 +11,7 @@
<tr>
<td class="table-messages-hide"></td>
<td data-bind="attr: { 'rowspan': parseInt(nrWarnings())+1 }, click: clearWarnings" class="table-messages-remove">
<a href="#" class="hover-button"><span class="glyphicon glyphicon-remove"></span></a>
<a href="#" class="hover-button" aria-label="$T('button-clear')"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></a>
</td>
</tr>
<!-- ko foreach: allWarnings -->
@@ -32,7 +32,7 @@
</td>
<!-- ko if: \$data.hasOwnProperty("clear") -->
<td class="table-messages-remove">
<a href="#" data-bind="click: clear" class="hover-button"><span class="glyphicon glyphicon-remove"></span></a>
<a href="#" data-bind="click: clear" class="hover-button" aria-label="$T('button-clear')"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></a>
</td>
<!-- /ko -->
</tr>
@@ -45,4 +45,4 @@
<!-- /ko -->
</tbody>
</table>
</div>
</div>
@@ -72,13 +72,13 @@
</div>
<!-- Modals -->
<div id="modal-options" class="modal fade" tabindex="-1">
<div id="modal-options" class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-options-title">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">&times;</span></button>
<a href="#" data-bind="click: loadStatusInfo, css: { 'rotate-refresh': !hasStatusInfo() }" title="$T('Glitter-interfaceRefresh')"><span class="glyphicon glyphicon-repeat"></span></a>
<h4 class="modal-title">$T('Glitter-statusInterfaceOptions')</h4>
<h4 class="modal-title" id="modal-options-title">$T('Glitter-statusInterfaceOptions')</h4>
</div>
<div class="modal-body">
<ul class="nav nav-tabs">
@@ -197,9 +197,12 @@
</div>
<div class="row options-function-box">
<div class="col-sm-6">
<a href="./api?mode=showlog&apikey=$apikey" target="_blank" class="btn btn-default" data-tooltip="true" data-placement="top" title="$T('Glitter-logText')">
<span class="glyphicon glyphicon-file"></span> $T('link-showLog')
</a>
<form method="post" action="$url('log')" target="_blank">
<input type="hidden" name="csrf_token" value="$csrf_token" />
<button type="submit" class="btn btn-default" data-tooltip="true" data-placement="top" title="$T('Glitter-logText')">
<span class="glyphicon glyphicon-file"></span> $T('link-showLog')
</button>
</form>
</div>
<div class="col-sm-6">
<div class="input-group" data-tooltip="true" data-placement="top" title="$T('logging')">
@@ -274,7 +277,7 @@
</div>
<!-- ko if: serverconnections().length > 0 -->
<table class="table table-hover table-server-connections" data-bind="visible: \$root.showActiveConnections()">
<table class="table table-hover table-server-connections" aria-label="$T('connections')" data-bind="visible: \$root.showActiveConnections()">
<thead>
<tr>
<th><strong>$T('article-id')</strong></th>
@@ -304,7 +307,7 @@
<a href="#" class="hover-button process-all-orphaned" data-bind="click: removeAllOrphaned">$T('Glitter-purgeOrphaned') <span class="glyphicon glyphicon-trash"></span></a>
<a href="#" class="hover-button process-all-orphaned" data-bind="click: addAllOrphaned">$T('Glitter-retryAllOrphaned') <span class="glyphicon glyphicon-plus-sign"></span></a>
<div class="clearfix"></div>
<table class="table table-hover table-striped">
<table class="table table-hover table-striped" aria-label="$T('Glitter-orphanedJobs')">
<thead>
<tr>
<th style="width: 30px;"></th>
@@ -333,7 +336,7 @@
</label>
</div>
<div class="form-group">
<label class="col-sm-6 control-label">$T('Glitter-interfaceRefresh')</label>
<label class="col-sm-6 control-label" for="refreshRate-option">$T('Glitter-interfaceRefresh')</label>
<div class="col-sm-4">
<select id="refreshRate-option" class="form-control" data-bind="value: refreshRate">
<option value="1">1 $T('second')</option>
@@ -351,9 +354,9 @@
</div>
</div>
<div class="form-group">
<label class="col-sm-6 control-label">$T('Glitter-queueItemLimit')</label>
<label class="col-sm-6 control-label" for="queue-pagination-limit">$T('Glitter-queueItemLimit')</label>
<div class="col-sm-4">
<select name="queue-pagination-limit" class="form-control" data-bind="value: queue.paginationLimit">
<select name="queue-pagination-limit" id="queue-pagination-limit" class="form-control" data-bind="value: queue.paginationLimit">
<option value="5">5 / $T('Glitter-page')</option>
<option value="10">10 / $T('Glitter-page')</option>
<option value="20">20 / $T('Glitter-page')</option>
@@ -366,9 +369,9 @@
</div>
</div>
<div class="form-group">
<label class="col-sm-6 control-label">$T('Glitter-historyItemLimit')</label>
<label class="col-sm-6 control-label" for="history-pagination-limit">$T('Glitter-historyItemLimit')</label>
<div class="col-sm-4">
<select name="history-pagination-limit" class="form-control" data-bind="value: history.paginationLimit">
<select name="history-pagination-limit" id="history-pagination-limit" class="form-control" data-bind="value: history.paginationLimit">
<option value="5">5 / $T('Glitter-page')</option>
<option value="10">10 / $T('Glitter-page')</option>
<option value="20">20 / $T('Glitter-page')</option>
@@ -381,9 +384,9 @@
</div>
</div>
<div class="form-group">
<label class="col-sm-6 control-label">$T('Glitter-dateFormat')</label>
<label class="col-sm-6 control-label" for="general-date-format">$T('Glitter-dateFormat')</label>
<div class="col-sm-4">
<select name="general-date-format" class="form-control" data-bind="value: dateFormat">
<select name="general-date-format" id="general-date-format" class="form-control" data-bind="value: dateFormat">
<option value="DD/MM/YYYY HH:mm"></option>
<option value="DD/MM/YYYY h:mma"></option>
<option value="MM/DD/YYYY HH:mm"></option>
@@ -399,12 +402,12 @@
</div>
</div>
<div class="form-group">
<label class="col-sm-6 control-label">
<label class="col-sm-6 control-label" for="general-extra-queue-columns">
$T('Glitter-showExtraQueueColumn')<br />
<span class="label label-warning">&gt; 1200 pixels</span>
</label>
<div class="col-sm-4">
<select name="general-extra-column" class="form-control-multiselect form-control" data-bind="selectedOptions: extraQueueColumns" multiple="true">
<select name="general-extra-column" id="general-extra-queue-columns" class="form-control-multiselect form-control" data-bind="selectedOptions: extraQueueColumns" multiple="true">
<option value="category">$T('category')</option>
<option value="priority">$T('priority')</option>
<option value="processing">$T('swtag-pp')</option>
@@ -414,12 +417,12 @@
</div>
</div>
<div class="form-group">
<label class="col-sm-6 control-label">
<label class="col-sm-6 control-label" for="general-extra-history-columns">
$T('Glitter-showExtraHistoryColumn')<br />
<span class="label label-warning">&gt; 1200 pixels</span>
</label>
<div class="col-sm-4">
<select name="general-extra-column" class="form-control-multiselect form-control" data-bind="selectedOptions: extraHistoryColumns" multiple="true">
<select name="general-extra-column" id="general-extra-history-columns" class="form-control-multiselect form-control" data-bind="selectedOptions: extraHistoryColumns" multiple="true">
<option value="category">$T('category')</option>
<option value="size">$T('size')</option>
<option value="speed">$T('Glitter-speed')</option>
@@ -485,12 +488,12 @@
</div>
</div>
<div id="modal-add-nzb" class="modal fade" tabindex="-1">
<div id="modal-add-nzb" class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-add-nzb-title">
<div class="modal-dialog">
<form class="modal-content" data-bind="submit: addNZB">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">$T('Glitter-addNZB')</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="modal-add-nzb-title">$T('Glitter-addNZB')</h4>
</div>
<div class="modal-body form-horizontal">
<div class="row">
@@ -524,29 +527,29 @@
<div class="clearfix"></div>
<hr />
<div class="form-group">
<label class="col-sm-4 control-label">$T('name')</label>
<label class="col-sm-4 control-label" for="nzbname">$T('name')</label>
<div class="col-sm-6">
<input type="text" name="nzbname" id="nzbname" placeholder="$T('Glitter-addnzbFilename')" class="form-control" />
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">$T('srv-password')</label>
<label class="col-sm-4 control-label" for="password">$T('srv-password')</label>
<div class="col-sm-6">
<input type="text" name="password" id="password" placeholder="$T('srv-optional')" class="form-control" />
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">$T('category')</label>
<label class="col-sm-4 control-label" for="add-nzb-category">$T('category')</label>
<div class="col-sm-6">
<select name="Category" class="form-control" data-bind="options: queue.categoriesList, optionsValue: 'catValue', optionsText: 'catText', optionsCaption: ''"></select>
<select name="Category" id="add-nzb-category" class="form-control" data-bind="options: queue.categoriesList, optionsValue: 'catValue', optionsText: 'catText', optionsCaption: ''"></select>
<span class="glyphicon glyphicon-tag"></span>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">$T('priority')</label>
<label class="col-sm-4 control-label" for="add-nzb-priority">$T('priority')</label>
<div class="col-sm-6">
<!-- This list is different from the one during download! -->
<select name="Priority" class="form-control">
<select name="Priority" id="add-nzb-priority" class="form-control">
<option value=""></option>
<option value="2">$T('pr-force')</option>
<option value="1">$T('pr-high')</option>
@@ -558,16 +561,16 @@
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">$T('swtag-pp')</label>
<label class="col-sm-4 control-label" for="add-nzb-processing">$T('swtag-pp')</label>
<div class="col-sm-6">
<select name="Processing" class="form-control" data-bind="options: queue.processingOptions, optionsValue: 'value', optionsText: 'name', optionsCaption: ''"></select>
<select name="Processing" id="add-nzb-processing" class="form-control" data-bind="options: queue.processingOptions, optionsValue: 'value', optionsText: 'name', optionsCaption: ''"></select>
<span class="glyphicon glyphicon-check"></span>
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">$T('eoq-scripts')</label>
<label class="col-sm-4 control-label" for="add-nzb-script">$T('eoq-scripts')</label>
<div class="col-sm-6">
<select name="Post-processing" class="form-control" data-bind="options: queue.scriptsList, optionsCaption: '', optionsValue: 'scriptValue', optionsText: 'scriptText', enable: (queue.scriptsList().length > 1)"></select>
<select name="Post-processing" id="add-nzb-script" class="form-control" data-bind="options: queue.scriptsList, optionsCaption: '', optionsValue: 'scriptValue', optionsText: 'scriptText', enable: (queue.scriptsList().length > 1)"></select>
<span class="glyphicon glyphicon-flash"></span>
</div>
</div>
@@ -577,12 +580,12 @@
</div>
</div>
<div id="modal-item-files" class="modal fade" tabindex="-1">
<div id="modal-item-files" class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-item-files-title">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title row-wrap-text" data-bind="text: filelist.filelist_name">$T('Glitter-loading')</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title row-wrap-text" id="modal-item-files-title" data-bind="text: filelist.filelist_name">$T('Glitter-loading')</h4>
</div>
<div class="modal-body">
<div id="modal-item-filelist">
@@ -645,12 +648,12 @@
</div>
</div>
<div id="modal-delete-queue-job" class="modal modal-delete-job fade" tabindex="-1">
<div id="modal-delete-queue-job" class="modal modal-delete-job fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-delete-queue-job-title">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title row-wrap-text">$T('removeNZB-Files')</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title row-wrap-text" id="modal-delete-queue-job-title">$T('removeNZB-Files')</h4>
</div>
<form data-bind="submit: queue.removeDownloads">
<div class="modal-body">
@@ -669,12 +672,12 @@
</div>
</div>
<div id="modal-delete-history-job" class="modal modal-delete-job fade" tabindex="-1">
<div id="modal-delete-history-job" class="modal modal-delete-job fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-delete-history-job-title">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title row-wrap-text">$T('nzo-delete')</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title row-wrap-text" id="modal-delete-history-job-title">$T('nzo-delete')</h4>
</div>
<form data-bind="submit: history.removeDownloads">
<div class="modal-body">
@@ -698,12 +701,12 @@
</div>
</div>
<div id="modal-retry-job" class="modal modal-small fade" tabindex="-1">
<div id="modal-retry-job" class="modal modal-small fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-retry-job-title">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">$T('Glitter-retryJob')</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="modal-retry-job-title">$T('Glitter-retryJob')</h4>
</div>
<form id="retry-job-form" data-bind="submit: history.retryJob">
<div class="modal-body">
@@ -740,24 +743,24 @@
</div>
</div>
<div id="history-script-log" class="modal fade" tabindex="-1">
<div id="history-script-log" class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="history-script-log-title">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">$T('Glitter-scriptLog')</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="history-script-log-title">$T('Glitter-scriptLog')</h4>
</div>
<div class="modal-body"></div>
<div class="modal-body"><pre></pre></div>
</div>
</div>
</div>
<div id="modal-help" class="modal fade">
<div id="modal-help" class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-help-title">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">$T('menu-help')</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="modal-help-title">$T('menu-help')</h4>
</div>
<div class="modal-body">
#include $webdir + "/../../Config/templates/staticcfg/images/logo-full.svg"#
@@ -790,12 +793,12 @@
</div>
</div>
<div id="modal-purge-history" class="modal modal-small fade" tabindex="-1">
<div id="modal-purge-history" class="modal modal-small fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-purge-history-title">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">$T('Glitter-clearHistory')</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="modal-purge-history-title">$T('Glitter-clearHistory')</h4>
</div>
<div class="modal-body">
<button type="button" class="btn btn-danger" data-bind="click: history.emptyHistory" data-action="history-purge-failed"><span class="glyphicon glyphicon-floppy-remove"></span> $T('purgeFailed')</button>
@@ -814,12 +817,12 @@
</div>
</div>
<div id="modal-custom-pause" class="modal modal-small fade" tabindex="-1">
<div id="modal-custom-pause" class="modal modal-small fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="modal-custom-pause-title">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">$T('Glitter-pauseFor')</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="$T('close')"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="modal-custom-pause-title">$T('Glitter-pauseFor')</h4>
</div>
<div class="modal-body">
<form data-bind="submit: saveCustomPause">
+18 -12
View File
@@ -47,6 +47,7 @@
</a>
<ul class="dropdown-menu">
<li><a href="#" data-action="sortRemainingAsc" data-bind="click: queue.queueSorting">$T('Glitter-sortRemaining')</a></li>
<li><a href="#" data-action="sortRemainingBytesAsc" data-bind="click: queue.queueSorting">$T('Glitter-sortRemainingBytesAsc')</a></li>
<li><a href="#" data-action="sortAgeAsc" data-bind="click: queue.queueSorting">$T('Glitter-sortAgeAsc')</a></li>
<li><a href="#" data-action="sortAgeDesc" data-bind="click: queue.queueSorting">$T('Glitter-sortAgeDesc')</a></li>
<li><a href="#" data-action="sortNameAsc" data-bind="click: queue.queueSorting">$T('Glitter-sortNameAsc')</a></li>
@@ -57,17 +58,17 @@
</div>
</div>
<div class="clearfix"></div>
<table class="table table-striped table-hover queue-table">
<table class="table table-striped table-hover queue-table" aria-label="$T('menu-queue')">
<thead>
<tr>
<th style="width: 25px;"></th>
<th></th>
<th scope="col" style="width: 25px;"><span class="sr-only">$T('status')</span></th>
<th scope="col"><span class="sr-only">$T('name')</span></th>
<!-- ko foreach: extraQueueColumns -->
<th class="table-header-extra"></th>
<th class="table-header-extra" scope="col"><span class="sr-only" data-bind="text: glitterTranslate.column[\$data]"></span></th>
<!-- /ko -->
<th class="table-header-progress" data-bind="css: { 'table-header-progress-smaller' : extraQueueColumns().length || displayCompact() }"></th>
<th style="width: 85px;"></th>
<th style="width: 60px;"></th>
<th class="table-header-progress" scope="col" data-bind="css: { 'table-header-progress-smaller' : extraQueueColumns().length || displayCompact() }"><span class="sr-only">$T('Glitter-progress')</span></th>
<th scope="col" style="width: 85px;"><span class="sr-only">$T('status')</span></th>
<th scope="col" style="width: 60px;"><span class="sr-only">$T('Glitter-actions')</span></th>
</tr>
</thead>
<!-- ko if: !hasQueue() -->
@@ -136,7 +137,7 @@
<!-- /ko -->
<td class="progress-indicator">
<div class="progress">
<div class="progress-bar progress-bar-info" data-bind="attr: { 'style': 'width: ' + percentage() + '%; background-color: ' + progressColor() + ';' }">
<div class="progress-bar progress-bar-info" role="progressbar" aria-label="$T('Glitter-progress')" aria-valuemin="0" aria-valuemax="100" data-bind="attr: { 'style': 'width: ' + percentage() + '%; background-color: ' + progressColor() + ';', 'aria-valuenow': percentage() }">
<strong data-bind="text: percentage() + '%'"></strong>
<i data-bind="text: missingText"></i>
</div>
@@ -230,15 +231,20 @@
</form>
<div class="input-group search-box" data-bind="visible: queue.hasQueueSearch" style="display: none;">
<input type="text" class="form-control" placeholder="$T('Glitter-search')" required data-bind="textInput: queue.searchTerm, event: { keydown: queue.clearSearchTerm }" />
<a data-bind="event: { mousedown: queue.clearSearchTerm }">
<input type="text" class="form-control" placeholder="$T('Glitter-search')" aria-label="$T('Glitter-search')" required data-bind="textInput: queue.searchTerm, event: { keydown: queue.clearSearchTerm }" />
<a href="#" data-tooltip="true" data-html="true" data-placement="right" title="$T('Glitter-searchExplain')" data-bind="click: queue.clearSearchTerm, attr: { 'aria-label': queue.searchTerm() ? '$T('Glitter-clearSearch')' : '$T('Glitter-search')' }">
<span class="glyphicon" data-bind="css: { 'glyphicon-search' : !queue.searchTerm(), 'glyphicon-remove' : queue.searchTerm() }"></span>
</a>
</div>
<ul class="pagination" data-bind="foreach: queue.pagination.allpages, visible: queue.pagination.hasPagination" style="display: none;">
<li data-bind="css: { active: isCurrent, disabled: isDots }, click: onclick">
<span data-bind="text: page"></span>
<li data-bind="css: { active: isCurrent, disabled: isDots }">
<!-- ko ifnot: isDots -->
<a href="#" data-bind="text: page, click: onclick, attr: { 'aria-current': isCurrent ? 'page' : null }"></a>
<!-- /ko -->
<!-- ko if: isDots -->
<span aria-hidden="true" data-bind="text: page"></span>
<!-- /ko -->
</li>
</ul>
+39 -27
View File
@@ -1,6 +1,6 @@
<!DOCTYPE html>
<!--#set $active_lang=$active_lang.replace('_', '-').lower()#-->
<html lang="$active_lang" <!--#if $rtl#-->dir="rtl"<!--#end if#--> id="sabnzbd" data-bind="filedrop: { overlaySelector: '.main-filedrop', onFileDrop: addNZBFromFile }">
<html lang="$active_lang" <!--#if $rtl#-->dir="rtl"<!--#end if#--> id="sabnzbd" data-color-scheme="$color_scheme" data-bind="filedrop: { overlaySelector: '.main-filedrop', onFileDrop: addNZBFromFile }">
<head>
<!--
Glitter V2
@@ -25,25 +25,23 @@
<meta name="msapplication-navbutton-color" content="#000000" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" sizes="76x76" href="./staticcfg/ico/apple-touch-icon-76x76-precomposed.png" />
<link rel="apple-touch-icon" sizes="120x120" href="./staticcfg/ico/apple-touch-icon-120x120-precomposed.png" />
<link rel="apple-touch-icon" sizes="152x152" href="./staticcfg/ico/apple-touch-icon-152x152-precomposed.png" />
<link rel="apple-touch-icon" sizes="180x180" href="./staticcfg/ico/apple-touch-icon-180x180-precomposed.png" />
<link rel="apple-touch-icon" sizes="192x192" href="./staticcfg/ico/android-192x192.png" />
<link rel="mask-icon" href="./staticcfg/ico/safari-pinned-tab.svg" color="#383F45">
<link rel="shortcut icon" type="image/ico" href="./staticcfg/ico/favicon.ico?v=$cache_buster" data-bind="attr: { 'href': SABIcon }" />
<link rel="apple-touch-icon" sizes="76x76" href="$url('staticcfg/ico/apple-touch-icon-76x76-precomposed.png', v=$cache_buster)" />
<link rel="apple-touch-icon" sizes="120x120" href="$url('staticcfg/ico/apple-touch-icon-120x120-precomposed.png', v=$cache_buster)" />
<link rel="apple-touch-icon" sizes="152x152" href="$url('staticcfg/ico/apple-touch-icon-152x152-precomposed.png', v=$cache_buster)" />
<link rel="apple-touch-icon" sizes="180x180" href="$url('staticcfg/ico/apple-touch-icon-180x180-precomposed.png', v=$cache_buster)" />
<link rel="apple-touch-icon" sizes="192x192" href="$url('staticcfg/ico/android-192x192.png', v=$cache_buster)" />
<link rel="mask-icon" href="$url('staticcfg/ico/safari-pinned-tab.svg', v=$cache_buster)" color="#383F45">
<link rel="shortcut icon" type="image/ico" href="$url('staticcfg/ico/favicon.ico', v=$cache_buster)" data-bind="attr: { 'href': SABIcon }" />
<link rel="stylesheet" type="text/css" href="./static/bootstrap/css/bootstrap.min.css?v=$cache_buster" />
<link rel="stylesheet" type="text/css" href="./static/stylesheets/glitter.css?v=$cache_buster" />
<link rel="stylesheet" type="text/css" href="./static/stylesheets/glitter.mobile.css?v=$cache_buster" media="all and (max-width: 768px)" />
<!--#if $color_scheme not in ('Light', '') #-->
<link rel="stylesheet" type="text/css" href="./static/stylesheets/colorschemes/${color_scheme}.css?v=$cache_buster"/>
<!--#end if#-->
<link rel="stylesheet" type="text/css" href="$url('static/bootstrap/css/bootstrap.min.css', v=$cache_buster)" />
<link rel="stylesheet" type="text/css" href="$url('static/stylesheets/glitter.css', v=$cache_buster)" />
<link rel="stylesheet" type="text/css" href="$url('static/stylesheets/glitter.mobile.css', v=$cache_buster)" media="all and (max-width: 768px)" />
<!-- Make translations available in scripts -->
<script type="text/javascript">
var apiKey = "$apikey";
var csrfToken = "$csrf_token";
var displayLang = "$active_lang";
var dateScriptUrl = "$url('static/javascripts/date.min.js', v=$cache_buster)";
var sabSpeedHistory = [$bytespersec_list];
var newRelease = "$new_release";
var newReleaseUrl = "$new_rel_url";
@@ -76,6 +74,14 @@
glitterTranslate.defaultText = "$T('default')";
glitterTranslate.noneText = "$T('None')";
glitterTranslate.moreText = "$T('Glitter-more')";
glitterTranslate.column = [];
glitterTranslate.column['category'] = "$T('category')";
glitterTranslate.column['priority'] = "$T('priority')";
glitterTranslate.column['processing'] = "$T('swtag-pp')";
glitterTranslate.column['scripts'] = "$T('eoq-scripts')";
glitterTranslate.column['age'] = "$T('nzo-age')";
glitterTranslate.column['size'] = "$T('size')";
glitterTranslate.column['speed'] = "$T('Glitter-speed')";
glitterTranslate.status = [];
glitterTranslate.status['DirectUnpack'] = "$T('opt-direct_unpack')";
glitterTranslate.status['Completed'] = "$T('post-Completed')";
@@ -116,21 +122,27 @@
glitterTranslate.priority['Stop'] = "$T('pr-stop')";
</script>
<!-- Inclusion is faster than external scripts. We load momentJS locale separately so failure won't break anything -->
<script type="text/javascript" src="$url('staticcfg/js/jquery-3.7.1.min.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('staticcfg/js/jquery-ui.min.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('static/javascripts/jquery.peity.min.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('static/javascripts/jquery.hotkeys.min.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('static/javascripts/moment-2.26.0.min.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('static/javascripts/knockout-3.5.1.min.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('static/javascripts/knockout-extensions.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('static/javascripts/search-query-parser.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('staticcfg/bootstrap/js/bootstrap.min.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('static/javascripts/glitter.basic.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('static/javascripts/glitter.main.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('static/javascripts/glitter.queue.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('static/javascripts/glitter.history.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('static/javascripts/glitter.filelist.pagination.js', v=$cache_buster)"></script>
<script type="text/javascript">
<!--#include raw $webdir + "/static/javascripts/jquery-3.5.1.min.js"#-->
<!--#include raw $webdir + "/static/javascripts/jquery-ui.min.js"#-->
<!--#include raw $webdir + "/static/javascripts/jquery.peity.min.js"#-->
<!--#include raw $webdir + "/static/javascripts/jquery.hotkeys.min.js"#-->
<!--#include raw $webdir + "/static/javascripts/moment-2.26.0.min.js"#-->
<!--#include raw $webdir + "/static/javascripts/knockout-3.5.1.min.js"#-->
<!--#include raw $webdir + "/static/javascripts/knockout-extensions.js"#-->
<!--#include raw $webdir + "/static/javascripts/search-query-parser.js"#-->
<!--#include raw $webdir + "/static/bootstrap/js/bootstrap.min.js"#-->
<!--#include $webdir + "/static/javascripts/glitter.js"#-->
jQuery(function () {
ko.applyBindings(new ViewModel(), document.getElementById("sabnzbd"));
});
</script>
<!--#if active_lang != 'en'#-->
<script type="text/javascript" src="./static/javascripts/momentjs_locale/${active_lang}.js?v=$cache_buster"></script>
<script type="text/javascript" src="$url('static/javascripts/momentjs_locale/' + $active_lang + '.js', v=$cache_buster)"></script>
<!--#end if#-->
</head>
<body>
File diff suppressed because one or more lines are too long.
@@ -23,15 +23,17 @@ if(isMobile) {
});
}
$.ajaxSetup({
headers: { "X-SABnzbd-CSRF": csrfToken }
});
// Basic API-call
function callAPI(data, timeout = 10000) {
// Fill basis var's
data.output = "json";
data.apikey = apiKey;
var ajaxQuery = $.ajax({
url: "./api",
type: "GET",
cache: false,
type: "POST",
data: data,
timeout: timeout
});
@@ -150,7 +150,6 @@ function HistoryListModel(parent) {
data.append("nzbfile", $(form.nzbFile)[0].files[0]);
data.append("value", $('#modal-retry-job input[name="retry_job_id"]').val());
data.append("password", $('#retry_job_password').val());
data.append("apikey", apiKey);
// Add
$.ajax({
@@ -184,15 +183,15 @@ function HistoryListModel(parent) {
// Clear searchterm
self.clearSearchTerm = function(data, event) {
// Was it escape key or click?
if(event.type === 'mousedown' || (event.keyCode && event.keyCode === 27)) {
if(event.type === 'click' || (event.keyCode && event.keyCode === 27)) {
// Set the loader so it doesn't flicker and then switch
self.isLoading(true)
self.searchTerm('');
}
// Was it click and the field is empty? Then we focus on the field
if(event.type === 'mousedown' && self.searchTerm() === '') {
if(event.type === 'click' && self.searchTerm() === '') {
$(event.target).parents('.search-box').find('input[type="text"]').focus()
return;
return false;
}
// Need to return true to allow typing
return true;
@@ -638,14 +637,13 @@ function HistoryModel(parent, data) {
$(this).hide()
} else {
// Info in modal
$('#history-script-log .modal-body').load($(this).attr('href'), function(result) {
// Set title and then remove it
$('#history-script-log .modal-title').text($(this).find("h3").text())
$(this).find("h3, title").remove()
$('#history-script-log').modal('show');
$('#history-script-log .modal-body pre').load($(this).attr('href'), function(result) {
var modal = $('#history-script-log');
modal.find('.modal-title').text(self.historyStatus.name());
modal.modal('show');
});
}
return false;
})
}
}
}
@@ -1,56 +0,0 @@
/******
Glitter V1
By Safihre (2015) - safihre@sabnzbd.org
Code extended from Shiny-template
Code examples used from Knockstrap-template
The setup is hierarchical, 1 main ViewModel that contains:
- ViewModel
- QueueListModel
- paginationModel
- QueueModel (item 1)
- QueueModel (item 2)
- ...
- QueueModel (item n+1)
- HistoryListModel
- paginationModel
- HistoryModel (item 1)
- HistoryModel (item 2)
- ...
- HistoryModel (item n+1)
- Fileslisting
- FileslistingModel (file 1)
- FileslistingModel (file 2)
- ...
- FileslistingModel (file n+1)
ViewModel also contains all the code executed on document ready and
functions responsible for the status information, adding NZB, etc.
The QueueModel/HistoryModel's get added to the list-models when
jobs are added or on switching of pages (using paginationModel).
Once added only the properties that changed during a refresh
get updated. In the history all the detailed information is only
updated when created and when the user clicks on a detail.
The Fileslisting is only populated and updated when it is opened
for one of the QueueModel's.
******/
#include raw $webdir + "/static/javascripts/glitter.basic.js"#
/**
GLITTER CODE
**/
\$(function() {
'use strict';
#include raw $webdir + "/static/javascripts/glitter.main.js"#
#include raw $webdir + "/static/javascripts/glitter.queue.js"#
#include raw $webdir + "/static/javascripts/glitter.history.js"#
#include raw $webdir + "/static/javascripts/glitter.filelist.pagination.js"#
// GO!!!
ko.applyBindings(new ViewModel(), document.getElementById("sabnzbd"));
});
@@ -425,7 +425,7 @@ function ViewModel() {
self.openCustomPauseTime = function() {
// Was it loaded already?
if (!Date.i18n) {
jQuery.getScript('./static/javascripts/date.min.js').then(function() {
jQuery.getScript(dateScriptUrl).then(function() {
// After loading we start again
self.openCustomPauseTime()
})
@@ -702,7 +702,6 @@ function ViewModel() {
data.append("priority", $('#modal-add-nzb select[name="Priority"]').val())
data.append("pp", $('#modal-add-nzb select[name="Processing"]').val())
data.append("script", $('#modal-add-nzb select[name="Post-processing"]').val())
data.append("apikey", apiKey);
// Add this one
$.ajax({
@@ -1224,7 +1223,7 @@ function ViewModel() {
}
});
$(document).bind('keydown', 'c', function(e) {
window.location.href = './config/';
window.location.href = './config';
});
$(document).bind('keydown', 's', function(e) {
// Update the data
@@ -1236,41 +1235,41 @@ function ViewModel() {
});
$(document).bind('keydown', 'shift+left', function(e) {
if($("body").hasClass("container-tabbed")) {
$('#history-tab.active > ul.pagination li.active').prev().click();
$('#queue-tab.active > ul.pagination li.active').prev().click();
$('#history-tab.active > ul.pagination li.active').prev().children('a').click();
$('#queue-tab.active > ul.pagination li.active').prev().children('a').click();
} else {
$('#history-tab > ul.pagination li.active').prev().click();
$('#queue-tab > ul.pagination li.active').prev().click();
$('#history-tab > ul.pagination li.active').prev().children('a').click();
$('#queue-tab > ul.pagination li.active').prev().children('a').click();
}
e.preventDefault();
});
$(document).bind('keydown', 'shift+right', function(e) {
if($("body").hasClass("container-tabbed")) {
$('#history-tab.active > ul.pagination li.active').next().click();
$('#queue-tab.active > ul.pagination li.active').next().click();
$('#history-tab.active > ul.pagination li.active').next().children('a').click();
$('#queue-tab.active > ul.pagination li.active').next().children('a').click();
} else {
$('#history-tab > ul.pagination li.active').next().click();
$('#queue-tab > ul.pagination li.active').next().click();
$('#history-tab > ul.pagination li.active').next().children('a').click();
$('#queue-tab > ul.pagination li.active').next().children('a').click();
}
e.preventDefault();
});
$(document).bind('keydown', 'shift+up', function(e) {
if($("body").hasClass("container-tabbed")) {
$('#history-tab.active > ul.pagination li').first().click();
$('#queue-tab.active > ul.pagination li').first().click();
$('#history-tab.active > ul.pagination li').first().children('a').click();
$('#queue-tab.active > ul.pagination li').first().children('a').click();
} else {
$('#history-tab > ul.pagination li').first().click();
$('#queue-tab > ul.pagination li').first().click();
$('#history-tab > ul.pagination li').first().children('a').click();
$('#queue-tab > ul.pagination li').first().children('a').click();
}
e.preventDefault();
});
$(document).bind('keydown', 'shift+down', function(e) {
if($("body").hasClass("container-tabbed")) {
$('#history-tab.active > ul.pagination li').last().click();
$('#queue-tab.active > ul.pagination li').last().click();
$('#history-tab.active > ul.pagination li').last().children('a').click();
$('#queue-tab.active > ul.pagination li').last().children('a').click();
} else {
$('#history-tab > ul.pagination li').last().click();
$('#queue-tab > ul.pagination li').last().click();
$('#history-tab > ul.pagination li').last().children('a').click();
$('#queue-tab > ul.pagination li').last().children('a').click();
}
e.preventDefault();
});
@@ -204,14 +204,14 @@ function QueueListModel(parent) {
// Clear searchterm
self.clearSearchTerm = function(data, event) {
// Was it escape key or click?
if(event.type === 'mousedown' || (event.keyCode && event.keyCode === 27)) {
if(event.type === 'click' || (event.keyCode && event.keyCode === 27)) {
self.isLoading(true)
self.searchTerm('');
}
// Was it click and the field is empty? Then we focus on the field
if(event.type === 'mousedown' && self.searchTerm() === '') {
if(event.type === 'click' && self.searchTerm() === '') {
$(event.target).parents('.search-box').find('input[type="text"]').focus()
return;
return false;
}
// Need to return true to allow typing
return true;
@@ -228,6 +228,10 @@ function QueueListModel(parent) {
sort = 'remaining';
dir = 'asc';
break;
case 'sortRemainingBytesAsc':
sort = 'remaining_bytes';
dir = 'asc';
break;
case 'sortAgeAsc':
sort = 'avg_age';
dir = 'desc';
File diff suppressed because one or more lines are too long.
File diff suppressed because one or more lines are too long.
@@ -1 +1 @@
@import url('Night.css') screen and (prefers-color-scheme: dark);
/* Placeholder — themes live in glitter.css; this file only populates the scheme dropdown */
@@ -1,163 +1 @@
/*
* Night theme overrides :root color tokens defined in glitter.css.
* Only structural/behavioural rules that can't be expressed as color tokens remain below.
*/
:root {
--clr-page-bg: black;
--clr-surface: #727272;
--clr-surface-alt: #444444;
--clr-surface-hover: #666666;
--clr-border: #808080;
--clr-border-subtle: #252525;
--clr-text: #EBEBEB;
--clr-text-muted: #D6D6D6;
--clr-error: #F95151;
--clr-input-bg: #555555;
--clr-input-border: #252525;
--clr-dropdown-bg: #727272;
--clr-modal-bg: #727272;
--clr-table-bg: #555555;
--clr-table-row-alt: #444444;
--clr-progress-track: #DADADA;
--clr-toggle-inactive: #666666;
}
/* Links and glyphicons inside links */
a, a:active,
a:hover,
a:focus,
.btn:not(.btn-danger):active,
.hover-button.glyphicon-play,
.hover-button.glyphicon-stop,
legend,
#modal-options legend label,
#modal-options legend a,
#modal-item-files .item-files-table .progress small,
.text-muted{
color: var(--clr-text);
}
/* Navbar needs structural dark-mode overrides */
nav {
background-color: #444444 !important;
border: 0 !important;
border-radius: var(--radius-lg);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
nav .btn {
background-color: #E4E4E4;
border-color: #5D5D5D !important;
}
nav .btn:active {
/* Restore bootstrap default */
color: #333 !important;
}
@media (max-width: 767px) {
nav {
background-color: black !important;
}
}
/* Collapse dropdown loses border in dark mode */
.navbar-collapse.in .dropdown-menu {
border: none;
}
/* Feedback slider needs explicit dark bg (not a card, not an input) */
#feedback-slider {
background-color: var(--clr-input-bg);
color: var(--clr-text);
}
/* Elements that must be white regardless of --clr-text */
.main-restarting,
.main-filedrop {
color: white !important;
}
/* Tab controls — dark-mode specific colours */
.max-speed-input-clear,
.max-speed-input-clear:hover,
.fileControls a {
color: black;
}
.nav-tabs>li.active>a,
.nav-tabs>li.active>a:focus,
.nav-tabs>li.active>a:hover,
.nav-tabs>li>a:hover,
.nav-tabs>li>a:focus {
background-color: #ddd;
color: #555 !important;
box-shadow: 0px -1px 1px 1px rgba(0, 0, 0, 0.15);
}
/* Opacity */
.hover-button,
.fileControls a:hover {
opacity: 0.7;
}
.form-control[disabled] {
opacity: 0.65;
}
/* Focus ring uses white glow in dark mode */
.form-control:focus,
input[type="submit"]:focus,
button:focus {
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
outline: initial;
}
/* Processing animation bars */
.processing-download > div {
background-color: var(--clr-text);
}
/* Legend / divider borders (dark-specific value, not matching any token) */
legend,
hr {
border-color: #C6C6C6 !important;
}
/* Slider handle */
.ui-slider .ui-slider-handle {
background-color: #969696;
border-color: #969696;
}
/* Compact layout progress shadow boost */
.container-compact .progress,
.container-compact .queue .progress-bar {
box-shadow: inset 1px 0px 1px rgba(0, 0, 0, 1);
}
.modal-footer {
border-top: 1px solid rgb(131 131 131);
}
/* Help table transparent bg override */
#modal-help table td,
#modal-help table {
background-color: transparent;
}
/* File items table structural */
#modal-item-files .item-files-table td {
border-bottom: none !important;
}
#modal-item-files .item-files-table {
border-bottom: 1px solid black;
}
/* History/queue tab switcher */
.history-queue-swicher .nav-tabs>li>a,
.history-queue-swicher .nav-tabs>li.active>a {
border-bottom: none;
margin-bottom: 1px;
}
/* Placeholder — themes live in glitter.css; this file only populates the scheme dropdown */
@@ -1,28 +1,40 @@
:root {
/* Follow the OS by default (Auto); forced by data-color-scheme below */
color-scheme: light dark;
/* Border radius scale */
--radius-sm: 4px; /* small elements: progress bars */
--radius-md: 6px; /* search bar, multi-edit toolbar, file controls */
--radius-lg: 8px; /* cards, modals, notification box */
/* Color palette — light mode defaults; override in Night.css */
--clr-page-bg: #E4E4E4; /* body/page background */
--clr-surface: #FFFFFF; /* cards, modals, notification box */
--clr-surface-alt: #F9F9F9; /* multi-edit toolbar, alternating rows */
--clr-surface-hover: #f6f6f6; /* hovered rows, inputs, buttons */
--clr-border: rgba(0,0,0,0.12); /* card outlines */
--clr-border-subtle: #EBEBEB; /* table row separators, inner borders */
--clr-text: #333333; /* primary body text */
--clr-text-muted: #888888; /* secondary / dimmed text */
--clr-error: red; /* errors, failed downloads */
--clr-input-bg: #FFFFFF; /* form inputs, buttons */
--clr-input-border: #CCCCCC; /* input/search borders */
--clr-dropdown-bg: #FFFFFF; /* dropdown menus */
--clr-modal-bg: #FFFFFF; /* modal body/footer */
--clr-table-bg: #F5F5F5; /* table and even-row background */
--clr-table-row-alt: #FDFDFD; /* odd striped row background */
--clr-progress-track: #f6f6f6; /* progress bar track */
--clr-toggle-active: #f9ca33; /* toggle knob track: on */
--clr-toggle-inactive: #aaaaaa; /* toggle knob track: off */
/* Color palette — light-dark(light value, dark value) */
--clr-page-bg: light-dark(#E4E4E4, black); /* body/page background */
--clr-surface: light-dark(#FFFFFF, #727272); /* cards, modals, notification box */
--clr-surface-alt: light-dark(#F9F9F9, #444444); /* multi-edit toolbar, alternating rows */
--clr-surface-hover: light-dark(#f6f6f6, #666666); /* hovered rows, inputs, buttons */
--clr-border: light-dark(rgba(0,0,0,0.12), #808080); /* card outlines */
--clr-border-subtle: light-dark(#EBEBEB, #252525); /* table row separators, inner borders */
--clr-text: light-dark(#333333, #EBEBEB); /* primary body text */
--clr-text-muted: light-dark(#888888, #D6D6D6); /* secondary / dimmed text */
--clr-error: light-dark(red, #F95151); /* errors, failed downloads */
--clr-input-bg: light-dark(#FFFFFF, #555555); /* form inputs, buttons */
--clr-input-border: light-dark(#CCCCCC, #252525); /* input/search borders */
--clr-dropdown-bg: light-dark(#FFFFFF, #727272); /* dropdown menus */
--clr-modal-bg: light-dark(#FFFFFF, #727272); /* modal body/footer */
--clr-table-bg: light-dark(#F5F5F5, #555555); /* table and even-row background */
--clr-table-row-alt: light-dark(#FDFDFD, #444444); /* odd striped row background */
--clr-progress-track: light-dark(#f6f6f6, #DADADA); /* progress bar track */
--clr-toggle-active: #f9ca33; /* toggle knob track: on */
--clr-toggle-inactive: light-dark(#aaaaaa, #666666); /* toggle knob track: off */
}
/* The server renders the configured scheme into this attribute (main.tmpl); empty/unknown = Auto */
html[data-color-scheme="light" i] {
color-scheme: light;
}
html[data-color-scheme="night" i] {
color-scheme: dark;
}
body {
@@ -40,12 +52,16 @@ h2 {
.container {
margin-top: 1em;
padding-left: 0;
padding-right: 0;
}
.main-navbar {
margin-bottom: 2px;
z-index: 999;
padding-left: 0;
padding-right: 0;
border: 0;
}
.navbar.main-navbar {
@@ -97,6 +113,25 @@ h2 {
color: white !important;
}
.dropdown-menu > li > form > button {
display: block;
width: 100%;
padding: 5px 15px 5px 25px;
border: 0;
background: transparent;
text-align: left;
font-weight: normal;
line-height: 1.42857143;
color: var(--clr-text);
white-space: nowrap;
}
@media (min-width: 768px) {
.dropdown-menu > li > form > button {
padding: 3px 20px;
}
}
.navbar-nav>li>a {
color: white !important;
opacity: 0.7;
@@ -165,7 +200,6 @@ li.dropdown {
line-height: 18px;
}
.max-speed-input-clear {
position: absolute;
top: 16px;
@@ -215,8 +249,8 @@ li.dropdown {
height: 24px;
top: -7px;
cursor: ew-resize;
background-color: #767676;
border: 1px solid white;
background-color: light-dark(#767676, #969696);
border: 1px solid light-dark(white, #969696);
margin-left: -.25em;
}
@@ -323,7 +357,7 @@ li.dropdown {
.main-restarting.in {
text-align: center;
opacity: 0.9;
color: black;
color: light-dark(black, white);
z-index: 2000;
padding: 15% 1em 1em;
}
@@ -364,7 +398,8 @@ li.dropdown {
width: 400px;
top: 40px;
left: -370px;
background: white;
background: light-dark(white, #555555);
color: var(--clr-text);
border: 1px solid rgba(0,0,0,.2);
border-radius: var(--radius-md);
transition-duration: 0.3s;
@@ -686,11 +721,14 @@ td.name .row-wrap-text {
}
.queue-table td.name .name-options {
display: block;
opacity: 0;
pointer-events: none;
position: absolute;
}
.queue-table td.name .name-options,
.queue-table td.name:hover .queue-item-password {
.queue-table td.name:hover .queue-item-password,
.queue-table td.name:focus-within .queue-item-password {
display: none;
}
@@ -708,20 +746,27 @@ td.name .row-wrap-text {
max-width: calc(100% - 75px);
}
.queue-table td.name:hover .row-wrap-text {
.queue-table td.name:hover .row-wrap-text,
.queue-table td.name:focus-within .row-wrap-text {
max-width: calc(100% - 125px);
/* Change for each size! */
}
.queue-table td.name:hover .direct-unpack {
.queue-table td.name:hover .direct-unpack,
.queue-table td.name:focus-within .direct-unpack {
display: none;
}
.queue-table td.name:hover .name-options {
.queue-table td.name:hover .name-options,
.queue-table td.name:focus-within .name-options {
display: block;
opacity: 1;
pointer-events: auto;
position: static;
}
.queue-table td.name:hover .glyphicon-folder-open {
.queue-table td.name:hover .glyphicon-folder-open,
.queue-table td.name:focus-within .glyphicon-folder-open {
width: 1.5em;
margin-left: 1px;
}
@@ -1186,11 +1231,8 @@ tr.queue-item>td:first-child>a {
font-weight: bold;
}
.mark-completed-link {
font-weight: bold !important;
color: #28a745 !important;
text-decoration: underline;
margin-left: 10px;
.mark-completed-btn {
margin: 4px 0;
}
.history-status-hidden {
@@ -1305,7 +1347,7 @@ tr.queue-item>td:first-child>a {
}
.processing-download > div {
background-color: #333;
background-color: var(--clr-text);
height: 100%;
width: 2px;
float: left;
@@ -1971,8 +2013,34 @@ input[name="nzbURL"] {
padding-top: 5px;
}
/* Tighten the gaps between the main containers */
.container-compact .main-navbar {
margin-top: 3px;
}
.container-compact:not(.container-tabbed) .main-content {
padding-top: 0;
margin-bottom: 15px;
}
.container-compact .queue,
.container-compact .history,
.container-compact .queue-messages {
padding: 4px 6px;
margin-bottom: 6px;
}
.container-compact .queue-footer,
.container-compact .history-footer {
padding: 0;
}
.container-compact .table {
margin-bottom: 3px;
}
.container-full-width .container {
width: calc(100% - 60px);
width: calc(100% - 40px);
}
/***
@@ -2287,11 +2355,18 @@ legend {
.pagination li.active a:hover,
.pagination li.active span:hover,
.pagination>li>span:hover {
background-color: var(--clr-table-row-alt);
background-color: var(--clr-surface-hover);
border: 1px solid var(--clr-border-subtle);
color: var(--clr-text);
}
.pagination>li>a:focus,
.pagination>li>a:hover {
color: var(--clr-text);
background-color: var(--clr-surface-hover);
border-color: var(--clr-border-subtle);
}
.pagination>li>a,
.pagination>li>span,
.pagination>.disabled>span,
@@ -2365,6 +2440,7 @@ legend {
.modal-footer {
margin-top: 0;
background-color: var(--clr-modal-bg);
border-top: 1px solid light-dark(#e5e5e5, rgb(131, 131, 131));
}
.modal-dialog {
@@ -2382,11 +2458,26 @@ legend {
}
legend {
border-color: var(--clr-text-muted);
border-color: light-dark(#888888, #C6C6C6);
}
hr {
border-color: var(--clr-text-muted);
border-color: light-dark(#888888, #C6C6C6);
}
/* Bootstrap's `a:focus { outline: 5px auto -webkit-focus-ring-color }` renders as a
heavy dark ring once color-scheme is declared. Replace it with a subtle themed
outline shown only for keyboard focus, matching the toggle-switch focus style. */
a:focus {
outline: none !important;
}
a:focus-visible {
outline: 2px solid var(--clr-toggle-active) !important;
outline-offset: 2px !important;
}
input[type="checkbox"] {
color-scheme: light;
}
/***
@@ -2402,7 +2493,9 @@ hr {
}
.dropdown-menu>li>a:hover,
.dropdown-menu>li>a:focus {
.dropdown-menu>li>a:focus,
.dropdown-menu>li>form>button:hover,
.dropdown-menu>li>form>button:focus {
background-color: var(--clr-surface-hover);
color: var(--clr-text);
}
@@ -2499,3 +2592,225 @@ h2 small {
color: var(--clr-text) !important;
opacity: 0.5 !important;
}
/***
Dark-mode structural rules
Colors live in the light-dark() tokens above; these are the rules that cannot
be expressed as a color value. The two blocks below MUST stay identical:
the first applies when Night is forced, the second when the OS is dark and Light is not forced.
***/
html[data-color-scheme="night" i] {
/* Links and glyphicons inside links */
a, a:active,
a:hover,
a:focus,
.btn:not(.btn-danger):active,
.hover-button.glyphicon-play,
.hover-button.glyphicon-stop,
legend,
#modal-options legend label,
#modal-options legend a,
#modal-item-files .item-files-table .progress small,
.text-muted {
color: var(--clr-text);
}
/* Navbar needs structural dark-mode overrides */
nav {
background-color: #444444 !important;
border-radius: var(--radius-lg);
}
nav .btn {
background-color: #E4E4E4;
border-color: #5D5D5D !important;
}
nav .btn:active {
/* Restore bootstrap default */
color: #333 !important;
}
@media (max-width: 767px) {
nav {
background-color: black !important;
}
}
/* Collapse dropdown loses border in dark mode */
.navbar-collapse.in .dropdown-menu {
border: none;
}
/* Tab controls — dark-mode specific colours */
.max-speed-input-clear,
.max-speed-input-clear:hover,
.fileControls a {
color: black;
}
.nav-tabs>li.active>a,
.nav-tabs>li.active>a:focus,
.nav-tabs>li.active>a:hover,
.nav-tabs>li>a:hover,
.nav-tabs>li>a:focus {
background-color: #ddd;
color: #555 !important;
box-shadow: 0px -1px 1px 1px rgba(0, 0, 0, 0.15);
}
/* Opacity */
.hover-button,
.fileControls a:hover {
opacity: 0.7;
}
.form-control[disabled] {
opacity: 0.65;
}
/* Focus ring uses white glow in dark mode */
.form-control:focus,
input[type="submit"]:focus,
button:focus {
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
outline: initial;
}
/* Compact layout progress shadow boost */
.container-compact .progress,
.container-compact .queue .progress-bar {
box-shadow: inset 1px 0px 1px rgba(0, 0, 0, 1);
}
/* Help table transparent bg override */
#modal-help table td,
#modal-help table {
background-color: transparent;
}
/* File items table structural */
#modal-item-files .item-files-table td {
border-bottom: none !important;
}
#modal-item-files .item-files-table {
border-bottom: 1px solid black;
}
/* History/queue tab switcher */
.history-queue-swicher .nav-tabs>li>a,
.history-queue-swicher .nav-tabs>li.active>a {
border-bottom: none;
margin-bottom: 1px;
}
}
@media (prefers-color-scheme: dark) {
html:not([data-color-scheme="light" i]) {
/* Links and glyphicons inside links */
a, a:active,
a:hover,
a:focus,
.btn:not(.btn-danger):active,
.hover-button.glyphicon-play,
.hover-button.glyphicon-stop,
legend,
#modal-options legend label,
#modal-options legend a,
#modal-item-files .item-files-table .progress small,
.text-muted {
color: var(--clr-text);
}
/* Navbar needs structural dark-mode overrides */
nav {
background-color: #444444 !important;
border-radius: var(--radius-lg);
}
nav .btn {
background-color: #E4E4E4;
border-color: #5D5D5D !important;
}
nav .btn:active {
/* Restore bootstrap default */
color: #333 !important;
}
@media (max-width: 767px) {
nav {
background-color: black !important;
}
}
/* Collapse dropdown loses border in dark mode */
.navbar-collapse.in .dropdown-menu {
border: none;
}
/* Tab controls — dark-mode specific colours */
.max-speed-input-clear,
.max-speed-input-clear:hover,
.fileControls a {
color: black;
}
.nav-tabs>li.active>a,
.nav-tabs>li.active>a:focus,
.nav-tabs>li.active>a:hover,
.nav-tabs>li>a:hover,
.nav-tabs>li>a:focus {
background-color: #ddd;
color: #555 !important;
box-shadow: 0px -1px 1px 1px rgba(0, 0, 0, 0.15);
}
/* Opacity */
.hover-button,
.fileControls a:hover {
opacity: 0.7;
}
.form-control[disabled] {
opacity: 0.65;
}
/* Focus ring uses white glow in dark mode */
.form-control:focus,
input[type="submit"]:focus,
button:focus {
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
outline: initial;
}
/* Compact layout progress shadow boost */
.container-compact .progress,
.container-compact .queue .progress-bar {
box-shadow: inset 1px 0px 1px rgba(0, 0, 0, 1);
}
/* Help table transparent bg override */
#modal-help table td,
#modal-help table {
background-color: transparent;
}
/* File items table structural */
#modal-item-files .item-files-table td {
border-bottom: none !important;
}
#modal-item-files .item-files-table {
border-bottom: 1px solid black;
}
/* History/queue tab switcher */
.history-queue-swicher .nav-tabs>li>a,
.history-queue-swicher .nav-tabs>li.active>a {
border-bottom: none;
margin-bottom: 1px;
}
}
}
@@ -151,6 +151,7 @@ tr.queue-item>td:first-child>a {
display: inline-block;
opacity: 1;
pointer-events: auto;
position: static;
}
.queue-table td.name .name-options small {
+12 -9
View File
@@ -1,16 +1,19 @@
<!DOCTYPE html>
<html lang="$active_lang">
<html lang="$active_lang" data-color-scheme="$color_scheme">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>$T('wizard-quickstart')</title>
<link rel="stylesheet" type="text/css" href="../staticcfg/bootstrap/css/bootstrap.min.css?v=$cache_buster"/>
<link rel="stylesheet" type="text/css" href="static/style.css?v=$cache_buster"/>
<!--#if $color_scheme not in ('Light', '') #-->
<link rel="stylesheet" type="text/css" href="../staticcfg/css/${color_scheme}.css?v=$cache_buster"/>
<!--#end if#-->
<link rel="shortcut icon" href="../staticcfg/ico/favicon.ico?v=$cache_buster" />
<script type="text/javascript" src="../staticcfg/js/jquery-3.5.1.min.js?v=$cache_buster"></script>
<script type="text/javascript" src="../staticcfg/bootstrap/js/bootstrap.min.js?v=$cache_buster"></script>
<link rel="stylesheet" type="text/css" href="$url('staticcfg/bootstrap/css/bootstrap.min.css', v=$cache_buster)"/>
<link rel="stylesheet" type="text/css" href="$url('wizard/static/style.css', v=$cache_buster)"/>
<link rel="shortcut icon" href="$url('staticcfg/ico/favicon.ico', v=$cache_buster)" />
<script type="text/javascript" src="$url('staticcfg/js/jquery-3.7.1.min.js', v=$cache_buster)"></script>
<script type="text/javascript" src="$url('staticcfg/bootstrap/js/bootstrap.min.js', v=$cache_buster)"></script>
<script type="text/javascript">
var csrfToken = "$csrf_token";
$.ajaxSetup({
headers: { "X-SABnzbd-CSRF": csrfToken }
});
</script>
</head>
<body>
<div id="logo">
+5 -3
View File
@@ -1,5 +1,6 @@
<!--#include $webdir + "/inc_top.tmpl"#-->
<form action="./one" method="post">
<form action="$url('wizard/one')" method="post">
<input type="hidden" name="csrf_token" value="$csrf_token" />
<div class="container">
<div id="inner">
<div id="content" class="bigger">
@@ -27,10 +28,10 @@
<hr />
<div class="row">
<div class="col-md-4 text-center">
<a class="btn btn-danger" href="../shutdown/?apikey=$apikey&amp;pid=$pid"><span class="glyphicon glyphicon-remove"></span> $T('wizard-exit')</a>
<button class="btn btn-danger" type="submit" form="shutdown-form"><span class="glyphicon glyphicon-remove"></span> $T('wizard-exit')</button>
</div>
<div class="col-md-4 text-center">
<a class="btn btn-default" href="../config/general/#config_backup_file"><span class="glyphicon glyphicon-open"></span> $T('restore-backup')</a>
<a class="btn btn-default" href="$url('config/general#config_backup_file')"><span class="glyphicon glyphicon-open"></span> $T('restore-backup')</a>
</div>
<div class="col-md-4 text-center">
<button class="btn btn-default">$T('wizard-start') <span class="glyphicon glyphicon-chevron-right"></span></button>
@@ -39,4 +40,5 @@
</div>
</div>
</form>
<form id="shutdown-form" method="post" action="$url('shutdown')"><input type="hidden" name="csrf_token" value="$csrf_token" /></form>
<!--#include $webdir + "/inc_bottom.tmpl"#-->
+6 -5
View File
@@ -1,5 +1,6 @@
<!--#include $webdir + "/inc_top.tmpl"#-->
<form action="./two" method="post" autocomplete="off">
<form action="$url('wizard/two')" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="$csrf_token" />
<div class="container">
<div id="inner">
<div id="content" class="bigger">
@@ -89,10 +90,10 @@
</div>
<div class="row">
<div class="col-sm-4">
<button id="serverTest" class="btn btn-default" data-toggle="tooltip" data-placement="left"><span class="glyphicon glyphicon-sort"></span> $T('wizard-button-testServer')</button>
<button id="serverTest" class="btn btn-default" data-toggle="tooltip" data-placement="left" aria-busy="false"><span class="glyphicon glyphicon-sort" aria-hidden="true"></span> $T('wizard-button-testServer')</button>
</div>
<div class="col-sm-8">
<div id="serverResponse" class="well well-sm">$T('wizard-server-text')</div>
<div id="serverResponse" class="well well-sm" role="status" aria-live="polite" aria-atomic="true">$T('wizard-server-text')</div>
</div>
</div>
@@ -102,12 +103,12 @@
<iframe style="float: right; width: 325px; height: 325px;" frameborder="0" src="https://sabnzbd.org/wizard#$active_lang"></iframe>
</div>
</div>
<input type="hidden" name="apikey" value="$apikey" />
<input type="hidden" name="enable" value="1">
</div>
<hr />
<div class="row">
<div class="col-xs-4 text-center">
<a class="btn btn-default" href="./index"><span class="glyphicon glyphicon-chevron-left"></span> $T('wizard-previous')</a>
<a class="btn btn-default" href="$url('wizard')"><span class="glyphicon glyphicon-chevron-left"></span> $T('wizard-previous')</a>
</div>
<div class="col-xs-4 text-center">
</div>
@@ -41,22 +41,25 @@ $(document).ready(function() {
return false;
}
$('#serverTest').attr('aria-busy', 'true');
$('#serverResponse').html(txtChecking);
$.getJSON(
"../api?mode=config&name=test_server&output=json",
$("form").serialize(),
function(result) {
$.ajax({
type: 'POST',
url: "../api?mode=config&name=test_server&output=json",
data: $("form").serialize(),
success: function(result) {
if (result.value.result) {
r = '<span class="success"><span class="glyphicon glyphicon-ok"></span> ' + result.value.message + '</span>';
r = '<span class="success"><span class="glyphicon glyphicon-ok" aria-hidden="true"></span> ' + result.value.message + '</span>';
setTestResult(true);
} else {
r = '<span class="failed"><span class="glyphicon glyphicon-minus-sign"></span> ' + result.value.message + '</span>';
r = '<span class="failed"><span class="glyphicon glyphicon-minus-sign" aria-hidden="true"></span> ' + result.value.message + '</span>';
setTestResult(false);
}
r = r.replace('https://sabnzbd.org/certificate-errors', '<a href="https://sabnzbd.org/certificate-errors" class="failed" target="_blank">https://sabnzbd.org/certificate-errors</a>')
$('#serverResponse').html(r);
$('#serverTest').attr('aria-busy', 'false');
}
);
});
return false;
});
@@ -88,4 +91,4 @@ $(document).ready(function() {
event.preventDefault();
}
})
});
});
+115 -13
View File
@@ -4,17 +4,31 @@
--radius-md: 6px; /* search bar, multi-edit toolbar, file controls */
--radius-lg: 8px; /* cards, modals, notification box */
/* Color palette — light mode defaults; overridden by Night.css */
--clr-page-bg: #E4E4E4;
--clr-surface: #FFFFFF;
--clr-surface-alt: #F5F5F5;
--clr-surface-hover: #E4E4E4;
--clr-border: rgba(0, 0, 0, 0.2);
--clr-text: #000000;
--clr-text-muted: #777777;
--clr-link: #555555;
/* Follow the OS by default (Auto); forced by data-color-scheme below */
color-scheme: light dark;
/* Color palette — light-dark(light value, dark value) */
--clr-page-bg: light-dark(#E4E4E4, black);
--clr-surface: light-dark(#FFFFFF, #303030);
--clr-surface-alt: light-dark(#F5F5F5, #444444);
--clr-surface-hover: light-dark(#E4E4E4, #666666);
--clr-border: light-dark(rgba(0, 0, 0, 0.2), #555555);
--clr-text: light-dark(#000000, #EBEBEB);
--clr-text-muted: light-dark(#777777, #c7c7c7);
--clr-link: light-dark(#555555, #63a7e1);
--clr-input-bg: light-dark(#FFFFFF, #555555);
--clr-input-border: light-dark(#cccccc, #252525);
--clr-toggle-active: #f9ca33;
--clr-toggle-inactive: #aaaaaa;
--clr-toggle-inactive: light-dark(#aaaaaa, #666666);
}
/* The server renders the configured scheme into this attribute; empty/unknown = Auto */
html[data-color-scheme="light" i] {
color-scheme: light;
}
html[data-color-scheme="night" i] {
color-scheme: dark;
}
body {
@@ -82,10 +96,10 @@ a[target="_blank"] {
color: #00cc22;
}
.failed {
color: red !important;
color: light-dark(red, #ff3333) !important;
}
#rightGreyText {
color: #ccc;
color: light-dark(#cccccc, #c7c7c7);
width: 100%;
text-align: right;
padding-top: 3px;
@@ -199,7 +213,25 @@ a:visited,
}
.btn {
min-width: 150px;
box-shadow: 1px 0px 1px rgba(0,0,0,.1);
box-shadow: 1px 0px 1px light-dark(rgba(0,0,0,.1), rgba(255,255,255,.1));
}
.btn-default,
input[type="text"],
input[type="number"],
input[type="email"],
input[type="password"],
input[type="url"],
select,
textarea {
background-color: var(--clr-input-bg);
color: var(--clr-text);
border-color: var(--clr-input-border);
}
::placeholder {
color: var(--clr-text) !important;
opacity: 0.5;
}
.btn .glyphicon,
a .glyphicon {
@@ -207,4 +239,74 @@ a .glyphicon {
}
small {
color: var(--clr-text-muted);
}
/***
Dark-mode structural rules
Colors live in the light-dark() tokens above; these are the rules that cannot
be expressed as a color value. The two blocks below MUST stay identical:
the first applies when Night is forced, the second when the OS is dark and Light is not forced.
***/
html[data-color-scheme="night" i] {
.language:hover,
.quoteBlock,
.server-disabled,
#serverResponse {
background-color: var(--clr-surface-alt) !important;
color: var(--clr-text) !important;
}
.quoteBlock a,
.help-block,
a.wizard-advanced-settings {
color: var(--clr-text);
}
#inner {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
/* Focus / active border */
.btn-default:focus,
.form-control:focus,
input:focus,
textarea:focus,
select:focus {
border-color: #707070 !important;
outline: initial !important;
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
}
}
@media (prefers-color-scheme: dark) {
html:not([data-color-scheme="light" i]) {
.language:hover,
.quoteBlock,
.server-disabled,
#serverResponse {
background-color: var(--clr-surface-alt) !important;
color: var(--clr-text) !important;
}
.quoteBlock a,
.help-block,
a.wizard-advanced-settings {
color: var(--clr-text);
}
#inner {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
/* Focus / active border */
.btn-default:focus,
.form-control:focus,
input:focus,
textarea:focus,
select:focus {
border-color: #707070 !important;
outline: initial !important;
box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.3) !important;
}
}
}
+5 -6
View File
@@ -12,8 +12,8 @@
<p>$T('wizard-tip4')</p>
<div class="quoteBlock">
<!--#for $url in $urls#-->
<a href="$url">$url</a><br />
<!--#for $access_url in $urls#-->
<a href="$access_url">$access_url</a><br />
<!--#end for#-->
</div>
@@ -22,13 +22,13 @@
<p><strong>$T('opt-complete_dir')</strong></p>
<div class="quoteBlock">
$complete_dir
<a href="${access_url}/config/folders#complete_dir" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
<a href="$url('config/folders#complete_dir')" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
</div>
<p><strong>$T('opt-download_dir')</strong></p>
<div class="quoteBlock">
$download_dir
<a href="${access_url}/config/folders#complete_dir" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
<a href="$url('config/folders#complete_dir')" class="indented"><span class="glyphicon glyphicon-cog"></span></a>
</div>
<hr/>
@@ -38,8 +38,7 @@
<hr />
<div class="row">
<div class="col-xs-12 text-center">
<input type="hidden" name="apikey" id="apikey" value="$apikey"/>
<a class="btn btn-success" href="$access_url">$T('wizard-goto') <span class="glyphicon glyphicon-chevron-right"></span></a>
<a class="btn btn-success" href="$url()">$T('wizard-goto') <span class="glyphicon glyphicon-chevron-right"></span></a>
</div>
</div>
</div>
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -4,7 +4,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Iamanro, 2026\n"
"Language-Team: Czech (https://app.transifex.com/sabnzbd/teams/111101/cs/)\n"
+1 -1
View File
@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+1 -1
View File
@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
+74 -49
View File
@@ -4,7 +4,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.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"
@@ -105,7 +105,6 @@ msgstr ""
msgid "SABnzbd shutdown finished"
msgstr ""
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr ""
@@ -219,12 +218,9 @@ msgstr ""
msgid "Connection Successful!"
msgstr ""
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr ""
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgid "Server %s took %d ms to respond. On high-latency connections, increasing 'Articles per request' to a value between 5 and 10 can improve download speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
#: sabnzbd/api.py
@@ -242,12 +238,12 @@ msgid "Default"
msgstr ""
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr ""
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr ""
@@ -514,15 +510,7 @@ msgid "Fatal error in Downloader"
msgstr ""
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr ""
#: sabnzbd/downloader.py
msgid "Login from too many different IP addresses to server %s [%s] - https://sabnzbd.org/multiple-adresses"
msgstr ""
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgid "Server %s reported: %s"
msgstr ""
#. Error message
@@ -686,11 +674,16 @@ msgid "Direct Write mode has been disabled because %s does not support sparse fi
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgid "Refused connection with hostname \"%s\" from:"
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgid "API Key incorrect, Use the api key from Config->General in your 3rd party program:"
msgstr ""
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr ""
#: sabnzbd/interface.py
@@ -698,16 +691,16 @@ msgid "API Key missing, please enter the api key from Config->General into your
msgstr ""
#: sabnzbd/interface.py
msgid "API Key incorrect, Use the api key from Config->General in your 3rd party program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr ""
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgid "Authentication failed, check username/password."
msgstr ""
#. Warning message
@@ -768,14 +761,6 @@ msgstr ""
msgid "Category folder cannot be a subfolder of the Temporary Download Folder."
msgstr ""
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr ""
#: sabnzbd/interface.py
msgid "Back"
msgstr ""
#. Warning message
#: sabnzbd/internetspeed.py
msgid "Internet Bandwidth of IPv4 significantly different from IPv6: %f MB/s versus %f MB/s"
@@ -1205,6 +1190,11 @@ msgstr ""
msgid "Queue finished"
msgstr ""
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr ""
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1439,6 +1429,21 @@ msgstr ""
msgid "If you get this error message again, please try a different number.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid "To keep using the low port, put a reverse proxy in front of SABnzbd instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1501,19 +1506,15 @@ msgstr ""
msgid "Unable to bind to port %s on %s. Some other software uses the port or SABnzbd is already running."
msgstr ""
#: sabnzbd/panic.py
msgid "Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr ""
#: sabnzbd/panic.py
msgid "Access denied"
msgstr ""
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr ""
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2080,6 +2081,10 @@ msgstr ""
msgid "Cancel"
msgstr ""
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr ""
@@ -2635,10 +2640,6 @@ msgstr ""
msgid "Web Interface Theme"
msgstr ""
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr ""
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr ""
@@ -3222,7 +3223,7 @@ msgid "Automatically sort jobs in the queue when a new job is added."
msgstr ""
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgid "The queue will resort every 30 seconds if % downloaded or Remaining Size is selected."
msgstr ""
#: sabnzbd/skintext.py
@@ -3343,7 +3344,7 @@ msgid "Naming"
msgstr ""
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
@@ -4236,6 +4237,14 @@ msgstr ""
msgid "Temp Folder"
msgstr ""
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid "Search by name, or refine with filters <code>cat:</code>, <code>status:</code> and <code>priority:</code> (Queue). For example: <code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr ""
@@ -4280,6 +4289,10 @@ msgstr ""
msgid "WARNING:"
msgstr ""
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr ""
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr ""
@@ -4316,6 +4329,14 @@ msgstr ""
msgid "Extra history columns"
msgstr ""
#: sabnzbd/skintext.py
msgid "Progress"
msgstr ""
#: sabnzbd/skintext.py
msgid "Actions"
msgstr ""
#: sabnzbd/skintext.py
msgid "page"
msgstr ""
@@ -4476,6 +4497,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr ""
+96 -66
View File
@@ -3,14 +3,14 @@
#
# Translators:
# Safihre <safihre@sabnzbd.org>, 2023
# Pavel C <quoing_transifex@mess.cz>, 2026
# Iamanro, 2026
# Pavel C <quoing_transifex@mess.cz>, 2026
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Iamanro, 2026\n"
"Last-Translator: Pavel C <quoing_transifex@mess.cz>, 2026\n"
"Language-Team: Czech (https://app.transifex.com/sabnzbd/teams/111101/cs/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -122,7 +122,6 @@ msgstr "SABnzbd %s spustěno"
msgid "SABnzbd shutdown finished"
msgstr "Ukončení činnosti programu SABnzbd bylo dokončeno"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Zaznamenán signál %s, ukládání a ukončení..."
@@ -269,15 +268,13 @@ msgstr "Server vyžaduje zadání uživatelského jména a hesla."
msgid "Connection Successful!"
msgstr "Připojení proběhlo úspěšně!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "Ověření se nezdařilo, zkontrolujte uživatelské jméno a heslo."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
"Příliš mnoho připojení pozastavte prosím stahování nebo to zkuste znovu "
"později"
#: sabnzbd/api.py
msgid "Resolving address"
@@ -294,12 +291,12 @@ msgid "Default"
msgstr "Výchozí"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Disk je plný! Vynucení pozastavení"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Probém s vytvořením souboru %s na disku"
@@ -600,20 +597,8 @@ msgid "Fatal error in Downloader"
msgstr "Závažná chyba ve Stahování"
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "Příliš mnoho spojení k serveru %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgid "Server %s reported: %s"
msgstr ""
"Příliš mnoho přihlášení ze různých IP adres na server %s [%s] "
"https://sabnzbd.org/multiple-adresses"
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Přihlášení k serveru %s se nezdařilo [%s]"
#. Error message
#: sabnzbd/downloader.py
@@ -801,14 +786,23 @@ msgstr ""
"Podrobnosti a možná řešení najdete zde: "
"https://sabnzbd.org/wiki/advanced/direct-write"
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Odmítnuto spojení z:"
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgstr "Odmítnuté spojení s hostem \"%s\" z:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"Nesprávný klíč API. Zadejte prosím klíč API z nabídky „Nastavení -> Obecné“ "
"do svého programu třetí strany:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr "Odmítnuto spojení z:"
#: sabnzbd/interface.py
msgid ""
"API Key missing, please enter the api key from Config->General into your 3rd"
@@ -818,21 +812,17 @@ msgstr ""
"svého programu třetí strany:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"Nesprávný klíč API. Zadejte prosím klíč API z nabídky „Nastavení -> Obecné“ "
"do svého programu třetí strany:"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr "Uživatel se přihlásil do webového rozhraní"
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr "Uživatel přihlášen"
msgid "Authentication failed, check username/password."
msgstr "Ověření se nezdařilo, zkontrolujte uživatelské jméno a heslo."
#. Warning message
#: sabnzbd/interface.py
@@ -893,14 +883,6 @@ msgid ""
"Category folder cannot be a subfolder of the Temporary Download Folder."
msgstr "Složka kategorie nesmí být podsložkou složky pro dočasné stahování."
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "CHYBA:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Zpět"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1363,6 +1345,11 @@ msgstr "Úkol neuspěšný"
msgid "Queue finished"
msgstr "Fronta dokončena"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr "Uživatel přihlášen"
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1609,6 +1596,23 @@ msgstr ""
"Pokud se vám tato chybová zpráva zobrazí znovu, zkuste prosím jiné číslo. "
"<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1697,19 +1701,16 @@ msgstr ""
"Nelze navázat spojení %s s portem %s. Tento port používá jiný software nebo "
"již běží SABnzbd."
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr "Nelze spustit webový prohlížeč, nejspíš nenalezen"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Přístup odepřen"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "Chyba %s: Je třeba zadat platné uživatelské jméno a heslo."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2277,6 +2278,10 @@ msgstr "Hostitel"
msgid "Cancel"
msgstr "Zrušit"
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr "Přihlásit"
@@ -2863,10 +2868,6 @@ msgstr "Port, na kterém má SABnzbd naslouchat."
msgid "Web Interface Theme"
msgstr "Motiv webového rozhraní"
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr "Vyberte motiv."
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "SABnzbd uživatelské jméno"
@@ -3566,8 +3567,10 @@ msgid "Automatically sort jobs in the queue when a new job is added."
msgstr "Automaticky řadit úlohy ve frontě, když je přidána nová úloha."
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgstr "Fronta se přeřadí každých 30 sekund, pokud je vybráno % staženo."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
#: sabnzbd/skintext.py
msgid "Propagation delay"
@@ -3705,8 +3708,8 @@ msgid "Naming"
msgstr "Pojmenování"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Kolik lze stáhnout tento měsíc (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4704,6 +4707,17 @@ msgstr "Volné místo"
msgid "Temp Folder"
msgstr "Dočasná složka"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Hromadné operace"
@@ -4748,6 +4762,10 @@ msgstr "V případě restartu SABnzbd tato obrazovka automaticky zmizí!"
msgid "WARNING:"
msgstr "VAROVÁNÍ:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "CHYBA:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Načíst"
@@ -4784,6 +4802,14 @@ msgstr "Další sloupce fronty"
msgid "Extra history columns"
msgstr "Další sloupce historie"
#: sabnzbd/skintext.py
msgid "Progress"
msgstr ""
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Akce"
#: sabnzbd/skintext.py
msgid "page"
msgstr "stránka"
@@ -4960,6 +4986,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr "Seřadit podle % staženo <small>Nejvíce&rarr;Nejméně</small>"
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Sort by Age <small>Oldest&rarr;Newest</small>"
+94 -63
View File
@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
"Language-Team: Danish (https://app.transifex.com/sabnzbd/teams/111101/da/)\n"
@@ -120,7 +120,6 @@ msgstr "SABnzbd %s startet"
msgid "SABnzbd shutdown finished"
msgstr "SABnzbd lukning udført"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Signal %s modtaget, gemmer og lukker..."
@@ -263,14 +262,13 @@ msgstr "Serveren kræver brugernavn og adgangskode."
msgid "Connection Successful!"
msgstr "Tilslutning lykkedes!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "Godkendelse mislykkedes, kontrollere brugernavn/adgangskode."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
"Alt for mange forbindelser, pause en download eller forsøg igen senere"
#: sabnzbd/api.py
msgid "Resolving address"
@@ -287,12 +285,12 @@ msgid "Default"
msgstr "Standard"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Disken er fuld! Pauser"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Diskfejl ved oprettelse af fil %s"
@@ -592,20 +590,8 @@ msgid "Fatal error in Downloader"
msgstr "Alvorlig fejl i Downloader"
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "Alt for mange forbindelser til serveren %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgid "Server %s reported: %s"
msgstr ""
"Login fra for mange forskellige IP-adresser til server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Det lykkedes ikke at logge på serveren %s [%s]"
#. Error message
#: sabnzbd/downloader.py
@@ -791,14 +777,23 @@ msgstr ""
"sparse-filer. For detaljer og mulige løsninger, se: "
"https://sabnzbd.org/wiki/advanced/direct-write"
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Afviste forbindelse fra:"
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgstr "Afviste forbindelse med værtsnavn \"%s\" fra:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"Forkert API-nøgle, anvend api-nøglen fra Konfiguration->Generelt i dit "
"tredjepartsprogram:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr "Afviste forbindelse fra:"
#: sabnzbd/interface.py
msgid ""
"API Key missing, please enter the api key from Config->General into your 3rd"
@@ -808,21 +803,17 @@ msgstr ""
"tredjepartsprogram:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"Forkert API-nøgle, anvend api-nøglen fra Konfiguration->Generelt i dit "
"tredjepartsprogram:"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr "Bruger logget på webgrænsefladen"
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr "Bruger logget ind"
msgid "Authentication failed, check username/password."
msgstr "Godkendelse mislykkedes, kontrollere brugernavn/adgangskode."
#. Warning message
#: sabnzbd/interface.py
@@ -884,14 +875,6 @@ msgid ""
msgstr ""
"Kategorimappe kan ikke være en undermappe i den midlertidige download-mappe."
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "FEJL:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Tilbage"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1352,6 +1335,11 @@ msgstr "Jobbet misllykedes"
msgid "Queue finished"
msgstr "Kø færdig"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr "Bruger logget ind"
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1595,6 +1583,23 @@ msgid ""
"If you get this error message again, please try a different number.<br>"
msgstr "Hvis du får denne fejlmeddelelse igen, prøv et andet portnummer.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1683,19 +1688,16 @@ msgstr ""
"Kan ikke binde til port %s på %s. En anden software bruger porten eller "
"SABnzbd kører allerede."
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr "Kan ikke starte browseren, sandsynligvis ikke fundet"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Adgang nægtet"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "Fejl %s: Du skal angive et gyldigt brugernavn og adgangskode."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2262,6 +2264,10 @@ msgstr "Vært"
msgid "Cancel"
msgstr "Annullér"
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr "Log in"
@@ -2848,10 +2854,6 @@ msgstr "Port som SABnzbd ska lytte på."
msgid "Web Interface Theme"
msgstr "Tema for webgrænseflade"
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr "Vælg et tema."
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "SABnzbd brugernavn"
@@ -3554,8 +3556,10 @@ msgid "Automatically sort jobs in the queue when a new job is added."
msgstr "Sortér automatisk jobs i køen, når et nyt job tilføjes."
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgstr "Køen vil sortere hver 30. sekund, hvis % downloadet er valgt."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
#: sabnzbd/skintext.py
msgid "Propagation delay"
@@ -3694,8 +3698,8 @@ msgid "Naming"
msgstr "Navngivning"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Hvor meget der kan downloades i denne måned (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4695,6 +4699,17 @@ msgstr "Ledig diskplads"
msgid "Temp Folder"
msgstr "Midlertidig mappe"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Multi-operationer"
@@ -4739,6 +4754,10 @@ msgstr "I tilfælde af SABnzbd genstart vil denne skærm forsvinde automatisk!"
msgid "WARNING:"
msgstr "ADVARSEL:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "FEJL:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Hent"
@@ -4775,6 +4794,14 @@ msgstr "Ekstra køkolonner"
msgid "Extra history columns"
msgstr "Ekstra historikkolonner"
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "Fremgang"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Handlinger"
#: sabnzbd/skintext.py
msgid "page"
msgstr "side"
@@ -4951,6 +4978,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr "Sortér efter % downloadet <small>Mest&rarr;Mindst</small>"
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Sortere efter alder <small>Ældst&rarr;Nyeste</small>"
+94 -67
View File
@@ -20,7 +20,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
"Language-Team: German (https://app.transifex.com/sabnzbd/teams/111101/de/)\n"
@@ -138,7 +138,6 @@ msgstr "SABnzbd %s gestartet"
msgid "SABnzbd shutdown finished"
msgstr "SABnzbd wurde beendet"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Signal %s erkannt. Wird gespeichert und beendet …"
@@ -288,16 +287,13 @@ msgstr "Server benötigt ein Benutzername und ein Passwort."
msgid "Connection Successful!"
msgstr "Verbindung erfolgreich hergestellt!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr ""
"Authentifizierung fehlgeschlagen. Überprüfen Sie Benutzername und Passwort."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
"Zu viele Verbindungen. Bitte halten Sie die Downloads an oder versuchen Sie "
"es später erneut."
#: sabnzbd/api.py
msgid "Resolving address"
@@ -314,12 +310,12 @@ msgid "Default"
msgstr "Standard"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Festplatte voll! Downloads werden angehalten."
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Festplattenfehler beim Anlegen der Datei %s"
@@ -625,20 +621,8 @@ msgid "Fatal error in Downloader"
msgstr "Schwerer Fehler im Downloader"
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "Zu viele Verbindungen zu Server %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgid "Server %s reported: %s"
msgstr ""
"Von zu vielen unteschiedlichen IP Adressen beim Server eingeloggt %s[%s] "
"https://sabnzbd.org/multiple-adresses"
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Anmelden beim Server fehlgeschlagen. %s [%s]"
#. Error message
#: sabnzbd/downloader.py
@@ -831,14 +815,23 @@ msgstr ""
"unterstützt. Einzelheiten und mögliche Lösungen finden Sie unter: "
"https://sabnzbd.org/wiki/advanced/direct-write"
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Abgelehnte Verbindung von:"
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgstr "Verbindung vom Host \"%s\" abgelehnt von:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"API-Schlüssel ungültig. Bitte API-Schlüssel aus Einstellungen->Allgemein in "
"die externe Anwendung eingeben:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr "Abgelehnte Verbindung von:"
#: sabnzbd/interface.py
msgid ""
"API Key missing, please enter the api key from Config->General into your 3rd"
@@ -848,21 +841,18 @@ msgstr ""
" externe Anwendung eingeben:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"API-Schlüssel ungültig. Bitte API-Schlüssel aus Einstellungen->Allgemein in "
"die externe Anwendung eingeben:"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr "Benutzer im Web-Interface angemeldet"
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr "Benutzer angemeldet"
msgid "Authentication failed, check username/password."
msgstr ""
"Authentifizierung fehlgeschlagen. Überprüfen Sie Benutzername und Passwort."
#. Warning message
#: sabnzbd/interface.py
@@ -925,14 +915,6 @@ msgstr ""
"Der Category-Ordner darf kein Unterordner des Temporärer Download-Ordners "
"sein."
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "FEHLER:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Zurück"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1400,6 +1382,11 @@ msgstr "Auftrag fehlgeschlagen"
msgid "Queue finished"
msgstr "Warteschlange abgearbeitet"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr "Benutzer angemeldet"
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1649,6 +1636,23 @@ msgstr ""
"Wenn Sie diesen Fehler wieder erhalten, probieren Sie eine andere "
"Nummer.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1737,6 +1741,11 @@ msgstr ""
"Konnte nicht an Port %s auf %s starten. Eine andere Software nutzt diesen "
"Port oder SABnzbd läuft bereits."
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
@@ -1744,15 +1753,6 @@ msgstr ""
"Der Standard-Browser konnte nicht gestartet werden, da er wahrscheinlich "
"nicht gefunden wurde."
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Zugriff verweigert"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr ""
"Fehler %s: Sie müssen einen gültigen Benutzername und ein Passwort angeben."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2323,6 +2323,10 @@ msgstr "Adresse"
msgid "Cancel"
msgstr "Abbrechen"
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr "Anmelden"
@@ -2914,10 +2918,6 @@ msgstr "Port, auf dem SABnzbd auf Anfragen warten soll."
msgid "Web Interface Theme"
msgstr "Benutzeroberfläche"
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr "Wählen Sie ein Theme."
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "SABnzbd-Benutzername"
@@ -3654,10 +3654,10 @@ msgstr ""
"Warteschlange automatisch sortieren wenn ein neuer Job hinzugefügt wird."
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
"Die Warteschlange wird alle 30 Sekunden neu sortiert, wenn % "
"heruntergeladen, ausgewählt ist."
#: sabnzbd/skintext.py
msgid "Propagation delay"
@@ -3800,8 +3800,8 @@ msgid "Naming"
msgstr "Benennung"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Wie viel kann in diesem Monat heruntergeladen werden (K/M/G)?"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4815,6 +4815,17 @@ msgstr "Freier Speicherplatz"
msgid "Temp Folder"
msgstr "Temporärer Ordner"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Mehrfach-Funktionen"
@@ -4859,6 +4870,10 @@ msgstr "Wenn SABnzbd neustartet, wird diese Anzeige automatisch verschwinden!"
msgid "WARNING:"
msgstr "WARNUNG:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "FEHLER:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Abrufen"
@@ -4895,6 +4910,14 @@ msgstr "Weitere Spalten bei der Warteschlange"
msgid "Extra history columns"
msgstr "Weitere Spalten bei der Verlaufsliste"
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "Fortschritt"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Aktionen"
#: sabnzbd/skintext.py
msgid "page"
msgstr "Seite"
@@ -5072,6 +5095,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr "Sortiere nach % heruntergeladen <small>Viel&rarr;Wenig</small>"
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Sortieren nach Alter <small>Älteste&rarr;Neuste</small>"
+94 -63
View File
@@ -9,7 +9,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
"Language-Team: Spanish (https://app.transifex.com/sabnzbd/teams/111101/es/)\n"
@@ -127,7 +127,6 @@ msgstr "SABnzbd %s comenzó"
msgid "SABnzbd shutdown finished"
msgstr "Cierre de SABnzbd terminado"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Señal %s capturado, guardando y saliendo..."
@@ -273,14 +272,13 @@ msgstr "El servidor necesita usuario y contraseña."
msgid "Connection Successful!"
msgstr "¡Conexión exitosa!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "Autenticación fallida, compruebe el usuario o la contraseña."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
"Demasiadas conexiones; pause las descargas o inténtelo de nuevo más tarde"
#: sabnzbd/api.py
msgid "Resolving address"
@@ -297,12 +295,12 @@ msgid "Default"
msgstr "Predeterminado"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Disco lleno! Pausando la cola"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Error de disco al crear el archivo %s"
@@ -610,20 +608,8 @@ msgid "Fatal error in Downloader"
msgstr "Error grave en el descargador"
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "Demasiadas conexiones con el servidor %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgid "Server %s reported: %s"
msgstr ""
"Inicio de sesión desde demasiadas direcciones IP diferentes en el servidor "
"%s [%s] - https://sabnzbd.org/multiple-adresses"
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Registraccion fallo para servidor %s [%s]"
#. Error message
#: sabnzbd/downloader.py
@@ -815,14 +801,23 @@ msgstr ""
"dispersos. Para más detalles y posibles soluciones, consulta: "
"https://sabnzbd.org/wiki/advanced/direct-write"
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Conexión rechazada de:"
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgstr "Se deniega la conexión con el nombre de equipo \"%s\" desde:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"Clave de API erróneo, favor ingresar la clave correcta desde Config->General"
" en tu aplicacion externa:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr "Conexión rechazada de:"
#: sabnzbd/interface.py
msgid ""
"API Key missing, please enter the api key from Config->General into your 3rd"
@@ -832,21 +827,17 @@ msgstr ""
"aplicacion externa:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"Clave de API erróneo, favor ingresar la clave correcta desde Config->General"
" en tu aplicacion externa:"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr "Usuario conectado a la interfaz web"
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr "Usuario conectado"
msgid "Authentication failed, check username/password."
msgstr "Autenticación fallida, compruebe el usuario o la contraseña."
#. Warning message
#: sabnzbd/interface.py
@@ -909,14 +900,6 @@ msgstr ""
"El directorio Categoría no puede ser un subdirectorio del directorio de "
"descargas temporal."
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "ERROR:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Atrás"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1391,6 +1374,11 @@ msgstr "Trabajo fallido"
msgid "Queue finished"
msgstr "Cola terminada"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr "Usuario conectado"
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1641,6 +1629,23 @@ msgstr ""
"Si obtiene este mensaje de error consecutivamente, por favor inténtelo de "
"nuevo con otro número.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1729,20 +1734,17 @@ msgstr ""
"No es posible vincular al puerto %s en %s. Otro software está utilizando el "
"puerto o SABnzbd ya se está ejecutando."
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr ""
"Imposible iniciar el navegador, probablemente no se le haya encontrado"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Acceso denegado"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "Error %s: Necesitas introducir un usuario y contraseña válidos."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2313,6 +2315,10 @@ msgstr "Equipo"
msgid "Cancel"
msgstr "Cancelar"
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr "Iniciar sesión"
@@ -2899,10 +2905,6 @@ msgstr "Puerto en que SABnzbd debería escuchar"
msgid "Web Interface Theme"
msgstr "Tema de la interfaz web"
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr "Elige un tema."
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "Usuario SABnzbd"
@@ -3627,8 +3629,10 @@ msgstr ""
"nueva."
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgstr "La cola se reordenará cada 30 segundos si se selecciona % descargado."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
#: sabnzbd/skintext.py
msgid "Propagation delay"
@@ -3772,8 +3776,8 @@ msgid "Naming"
msgstr "Nombrado"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Cantidad de descarga permitida este mes (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4784,6 +4788,17 @@ msgstr "Espacio libre"
msgid "Temp Folder"
msgstr "Carpeta temporal"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Op.Múltiples"
@@ -4830,6 +4845,10 @@ msgstr ""
msgid "WARNING:"
msgstr "AVISO:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "ERROR:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Obtener"
@@ -4866,6 +4885,14 @@ msgstr "Columnas adicionales de la cola"
msgid "Extra history columns"
msgstr "Columnas adicionales del historial"
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "Progreso"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Acciones"
#: sabnzbd/skintext.py
msgid "page"
msgstr "página"
@@ -5043,6 +5070,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr "Ordenar por % descargado <small>Mayor&rarr;Menor</small>"
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Ordenar por Fecha <small>Más viejo&rarr;Más nuevo</small>"
+92 -58
View File
@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
"Language-Team: Finnish (https://app.transifex.com/sabnzbd/teams/111101/fi/)\n"
@@ -119,7 +119,6 @@ msgstr "SABnzbd %s käynnistetty"
msgid "SABnzbd shutdown finished"
msgstr "SABnzbd sammutus valmis"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Signaali %s kaapattu, tallennetaan ja lopetetaan..."
@@ -251,13 +250,13 @@ msgstr "Palvelin vaatii käyttäjänimen ja salasanan."
msgid "Connection Successful!"
msgstr "Yhdistäminen onnistui!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "Varmennus epäonnistui, tarkista käyttäjänimi/salasana."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgstr "Liikaa yhteyksiä, keskeytä lataaminen tai yritä myöhemmin uudelleen"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
#: sabnzbd/api.py
msgid "Resolving address"
@@ -274,12 +273,12 @@ msgid "Default"
msgstr "Oletus"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Levy täynnä! Pakotetaan keskeytys"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Levyvirhe luotaessa tiedostoa %s"
@@ -562,19 +561,9 @@ msgid "Fatal error in Downloader"
msgstr ""
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "Liikaa yhteyksiä palvelimelle %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgid "Server %s reported: %s"
msgstr ""
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Kirjautuminen palvelimelle %s epäonnistui [%s]"
#. Error message
#: sabnzbd/downloader.py
msgid "Connecting %s@%s failed, message=%s"
@@ -753,11 +742,20 @@ msgid ""
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgid "Refused connection with hostname \"%s\" from:"
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"API avain virheellinen, käytä Asetukset->Yleiset löytyvää api avainta "
"käyttämääsi kolmannen osapuolen ohjelmaan:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr ""
#: sabnzbd/interface.py
@@ -769,21 +767,17 @@ msgstr ""
"käyttämääsi kolmannen osapuolen ohjelmaan:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"API avain virheellinen, käytä Asetukset->Yleiset löytyvää api avainta "
"käyttämääsi kolmannen osapuolen ohjelmaan:"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr "Käyttäjä kirjautui sisään web-käyttöliittymään"
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr "Käyttäjä kirjautui sisään"
msgid "Authentication failed, check username/password."
msgstr "Varmennus epäonnistui, tarkista käyttäjänimi/salasana."
#. Warning message
#: sabnzbd/interface.py
@@ -844,14 +838,6 @@ msgid ""
"Category folder cannot be a subfolder of the Temporary Download Folder."
msgstr ""
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "VIRHE:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Takaisin"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1298,6 +1284,11 @@ msgstr "Lataus epäonnistui"
msgid "Queue finished"
msgstr "Jono valmistunut"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr "Käyttäjä kirjautui sisään"
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1541,6 +1532,23 @@ msgid ""
"If you get this error message again, please try a different number.<br>"
msgstr "Jos saat tämän virhesanoman uudestaan, kokeile toista numeroa.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1627,19 +1635,16 @@ msgid ""
"SABnzbd is already running."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr "Selainta ei voida käynnistää, todennäköisesti ei löydy"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Ei käyttöoikeutta"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "Virhe %s: Syötä kelvollinen käyttäjänimi ja salasana."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2206,6 +2211,10 @@ msgstr "Isäntä"
msgid "Cancel"
msgstr "Peruuta"
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr "Kirjaudu sisään"
@@ -2788,10 +2797,6 @@ msgstr "Portti jota SABnzbdn tulisi kuunnella."
msgid "Web Interface Theme"
msgstr ""
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr ""
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "SABnzbd käyttäjänimi"
@@ -3476,7 +3481,9 @@ msgid "Automatically sort jobs in the queue when a new job is added."
msgstr ""
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
#: sabnzbd/skintext.py
@@ -3612,8 +3619,8 @@ msgid "Naming"
msgstr "Nimeäminen"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Kuinka paljon voidaan ladata tässä kuussa (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4576,6 +4583,17 @@ msgstr "Vapaa tila"
msgid "Temp Folder"
msgstr "Väliaikaiskansio"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Monioperaatiot"
@@ -4621,6 +4639,10 @@ msgstr ""
msgid "WARNING:"
msgstr "VAROITUS:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "VIRHE:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Nouda"
@@ -4657,6 +4679,14 @@ msgstr ""
msgid "Extra history columns"
msgstr ""
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "Edistyminen"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Toiminnot"
#: sabnzbd/skintext.py
msgid "page"
msgstr "sivu"
@@ -4828,6 +4858,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Järjestä iän mukaan <small>Vanhin&rarr;Uusin</small>"
+119 -71
View File
@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Fred L <88com88@gmail.com>, 2026\n"
"Language-Team: French (https://app.transifex.com/sabnzbd/teams/111101/fr/)\n"
@@ -128,7 +128,6 @@ msgstr "SABnzbd %s démarré"
msgid "SABnzbd shutdown finished"
msgstr "Arrêt de SABnzbd terminé"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Signal %s intercepté, enregistrement et fermeture en cours..."
@@ -277,15 +276,17 @@ msgstr "Le serveur requiert un identifiant et un mot de passe."
msgid "Connection Successful!"
msgstr "Connexion réussie!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "Echec d'authentification, vérifiez les identifiant/mot de passe."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
"Trop de connexions, veuillez mettre en pause le téléchargement ou essayer "
"plus tard"
"Le serveur %s a mis %d ms à répondre. Sur les connexions à forte latence, "
"augmenter le paramètre « Articles par requête » à une valeur comprise entre "
"5 et 10 peut améliorer la vitesse de téléchargement. Voir : "
"https://sabnzbd.org/wiki/advanced/nntp-pipelining"
#: sabnzbd/api.py
msgid "Resolving address"
@@ -302,12 +303,12 @@ msgid "Default"
msgstr "Par défaut"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Disque plein ! Pause forcée"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Erreur de disque lors de la création du fichier %s"
@@ -614,20 +615,8 @@ msgid "Fatal error in Downloader"
msgstr "Erreur fatale dans le Téléchargeur"
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "Trop de connexions au serveur %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgstr ""
"Connexion au serveur %s [%s] à partir de trop d'adresses IP différentes - "
"https://sabnzbd.org/multiple-adresses"
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Échec de la connexion au serveur %s [%s]"
msgid "Server %s reported: %s"
msgstr "Le serveur %s a indiqué : %s"
#. Error message
#: sabnzbd/downloader.py
@@ -820,14 +809,23 @@ msgstr ""
"fichiers fragmentés. Pour plus d'informations et les solutions possibles, "
"consultez : https://sabnzbd.org/wiki/advanced/direct-write"
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Connexion refusée de:"
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgstr "Connexion refusée avec le nom d'hôte \"%s\" à partir de :"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"Clé API incorrecte, utilisez la clé API de la configuration générale dans "
"votre application tierce :"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr "Connexion refusée de:"
#: sabnzbd/interface.py
msgid ""
"API Key missing, please enter the api key from Config->General into your 3rd"
@@ -837,21 +835,17 @@ msgstr ""
" application tierce :"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"Clé API incorrecte, utilisez la clé API de la configuration générale dans "
"votre application tierce :"
msgid "Too many failed login attempts, try again later."
msgstr "Trop de tentatives de connexion échouées, réessayer ultérieurement."
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr "Tentative de connexion refusée, trop d'échecs de %s"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr "Utilisateur connecté à l'interface web"
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr "Utilisateur connecté"
msgid "Authentication failed, check username/password."
msgstr "Echec d'authentification, vérifiez les identifiant/mot de passe."
#. Warning message
#: sabnzbd/interface.py
@@ -914,14 +908,6 @@ msgstr ""
"Le dossier de catégorie ne peut pas être un sous-dossier du dossier de "
"téléchargement temporaire."
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "ERREUR:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Retour"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1389,6 +1375,11 @@ msgstr "La tâche a échoué"
msgid "Queue finished"
msgstr "File d'attente terminée"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr "Utilisateur connecté"
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1634,6 +1625,32 @@ msgstr ""
"Si vous obtenez ce message d'erreur à nouveau, veuillez essayer un nombre "
"différent.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
"\n"
" SABnzbd n'est pas autorisé à utiliser le port %s sur %s.<br>\n"
" Sur la plupart des systèmes, les numéros de port faibles sont réservés aux processus privilégiés.\n"
" le port est donc disponible, mais ne peut pas être utilisé.<br>\n"
" <br>\n"
" Lancez SABnzbd avec les privilèges requis pour ce port, ou redémarrez-le\n"
" en lui attribuant un numéro de port supérieur ou égal à 1024."
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
"Pour continuer à utiliser un port privilégié, mettez un proxy inverse devant"
" SABnzbd.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1722,21 +1739,18 @@ msgstr ""
"Impossible de lier le port %s sur %s. Un autre logiciel utilise le port ou "
"SABnzbd est déjà en cours d'exécution."
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
"Impossible de se lier au port %s sur %s. Les ports inférieurs à 1024 "
"demandent des privilèges élevés."
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr "Impossible de lancer le navigateur web, probablement pas trouvé"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Accès refusé"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr ""
"Erreur %s: vous devez fournir un nom d'utilisateur et un mot de passe "
"valide."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -1871,7 +1885,7 @@ msgstr "Échec de la suppression de %s"
#: sabnzbd/postproc.py
msgid "Removed %s files with unwanted extensions"
msgstr ""
msgstr "Suppression de %s fichiers comportant des extensions indésirables"
#. Error message
#: sabnzbd/powersup.py
@@ -2308,6 +2322,10 @@ msgstr "Hôte"
msgid "Cancel"
msgstr "Annuler"
#: sabnzbd/skintext.py
msgid "Close"
msgstr "Fermer"
#: sabnzbd/skintext.py
msgid "Log in"
msgstr "Se connecter"
@@ -2899,10 +2917,6 @@ msgstr "Port que SABnzbd doit surveiller."
msgid "Web Interface Theme"
msgstr "Thème de l'interface web"
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr "Choisissez un thème."
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "Identifiant SABnzbd"
@@ -3635,10 +3649,12 @@ msgstr ""
"ajoutée."
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
"La file d'attente sera triée toutes les 30 secondes si le % de "
"téléchargement est sélectionné."
"La file d'attente sera retriée toutes les 30 secondes si % téléchargé ou "
"Taille restante est sélectionné."
#: sabnzbd/skintext.py
msgid "Propagation delay"
@@ -3782,8 +3798,10 @@ msgid "Naming"
msgstr "Appellation"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Combien peut-être télécharger ce mois (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
"Quantité de données pouvant être téléchargées durant ce cycle de quota "
"(K/M/G)"
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4798,6 +4816,20 @@ msgstr "Espace libre"
msgid "Temp Folder"
msgstr "Dossier temporaire"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr "Effacer la recherche"
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
"Rechercher par nom, ou affiner avec des filtres <code>cat :</code>, "
"<code>statut :</code> et <code>priorité :</code> (file d'attente). Par "
"exemple : <code>mon show cat:tv</code>"
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Multi-Operations"
@@ -4808,7 +4840,7 @@ msgstr "Maintenez la touche Maj pour sélectionner une plage"
#: sabnzbd/skintext.py
msgid "Select job"
msgstr ""
msgstr "Sélectionner la tâche"
#: sabnzbd/skintext.py
msgid "Check all"
@@ -4843,6 +4875,10 @@ msgstr ""
msgid "WARNING:"
msgstr "AVERTISSEMENT :"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "ERREUR:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Charger"
@@ -4879,6 +4915,14 @@ msgstr "Colonnes de file d'attente supplémentaires"
msgid "Extra history columns"
msgstr "Colonnes d'historique supplémentaires"
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "Avancement"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Actions"
#: sabnzbd/skintext.py
msgid "page"
msgstr "page"
@@ -5058,6 +5102,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr "Trier par % téléchargé <small>Most&rarr;Least</small>"
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr "Trier par Taille restante <small>Plus petit&rarr;Plus grand</small>"
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Trier par Age <small>Moins récent&rarr;Plus récent</small>"
+94 -62
View File
@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
"Language-Team: Hebrew (https://app.transifex.com/sabnzbd/teams/111101/he/)\n"
@@ -115,7 +115,6 @@ msgstr "SABnzbd %s התחיל"
msgid "SABnzbd shutdown finished"
msgstr "כיבוי SABnzbd הסתיים"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "אות %s נתפס, שומר ויוצא…"
@@ -255,13 +254,13 @@ msgstr ".השרת דורש שם משתמש וסיסמה"
msgid "Connection Successful!"
msgstr "חיבור מוצלח!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "אימות נכשל, בדוק שם משתמש/סיסמה."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgstr "יותר מדי חיבורים, אנא השהה הורדה או נסה שוב מאוחר יותר"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
#: sabnzbd/api.py
msgid "Resolving address"
@@ -278,12 +277,12 @@ msgid "Default"
msgstr "ברירת מחדל"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "דיסק מלא! מאלץ השהיה"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "שגיאת דיסק ביצירת קובץ %s"
@@ -573,20 +572,8 @@ msgid "Fatal error in Downloader"
msgstr "שגיאה גורלית במורידן"
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "יותר מדי חיבורים לשרת %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgid "Server %s reported: %s"
msgstr ""
"כניסה מיותר מדי כתובות IP שונות אל שרת %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "כניסה נכשלה עבור שרת %s [%s]"
#. Error message
#: sabnzbd/downloader.py
@@ -769,14 +756,21 @@ msgstr ""
"מצב Direct Write הושבת מכיוון ש-%s אינו תומך בקבצים דלילים. לפרטים ולפתרונות"
" אפשריים, ראה: https://sabnzbd.org/wiki/advanced/direct-write"
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "חיבור מסורב מאת:"
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgstr "חיבור מסורב עם שם המארח \"%s\" מאת:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr "מפתח API שגוי, השתמש במפתח ה־API מתצורה->כללי בתוכנית הצד השלישי שלך:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr "חיבור מסורב מאת:"
#: sabnzbd/interface.py
msgid ""
"API Key missing, please enter the api key from Config->General into your 3rd"
@@ -786,19 +780,17 @@ msgstr ""
"שלך:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr "מפתח API שגוי, השתמש במפתח ה־API מתצורה->כללי בתוכנית הצד השלישי שלך:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr "משתמש התחבר לממשק הרשת"
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr "משתמש התחבר"
msgid "Authentication failed, check username/password."
msgstr "אימות נכשל, בדוק שם משתמש/סיסמה."
#. Warning message
#: sabnzbd/interface.py
@@ -859,14 +851,6 @@ msgid ""
"Category folder cannot be a subfolder of the Temporary Download Folder."
msgstr "תיקיית קטגוריה אינה יכולה להיות תת־תיקייה של תיקיית ההורדות הזמניות."
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "שגיאה:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "הקודם"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1320,6 +1304,11 @@ msgstr "עבודה נכשלה"
msgid "Queue finished"
msgstr "תור הסתיים"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr "משתמש התחבר"
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1563,6 +1552,23 @@ msgid ""
"If you get this error message again, please try a different number.<br>"
msgstr "אם אתה מקבל את הודעת השגיאה הזו שוב, אנא נסה מספר שונה.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1651,19 +1657,16 @@ msgstr ""
"לא היה ניתן לקשר את פתחה %s על %s. איזשהי תוכנה אחרת משתמשת בפתחה או SABnzbd"
" כבר רץ."
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr "לא היה ניתן להפעיל את הדפדפן, כנראה שהוא לא נמצא"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "גישה נדחתה"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "שגיאה %s: אתה צריך לספק שם משתמש וסיסמה תקפים."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2230,6 +2233,10 @@ msgstr "מארח"
msgid "Cancel"
msgstr "ביטול"
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr "התחבר"
@@ -2812,10 +2819,6 @@ msgstr "פתחה אשר SABnzbd צריך להאזין אליה."
msgid "Web Interface Theme"
msgstr "ערכת נושא של ממשק רשת"
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr "בחר ערכת נושא."
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "שם משתמש SABnzbd"
@@ -3494,8 +3497,10 @@ msgid "Automatically sort jobs in the queue when a new job is added."
msgstr "מיין עבודות בתור באופן אוטומטי כאשר עבודה חדשה מתווספת."
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgstr "התור ימוין כל 30 שניות אם האפשרות % ירד נבחרה."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
#: sabnzbd/skintext.py
msgid "Propagation delay"
@@ -3630,8 +3635,8 @@ msgid "Naming"
msgstr "מתן שמות"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "כמה ניתן להוריד החודש (ק״ב/מ״ב/ג״ב)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4613,6 +4618,17 @@ msgstr "שטח פנוי"
msgid "Temp Folder"
msgstr "תיקייה זמנית"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "רב־תפעולים"
@@ -4657,6 +4673,10 @@ msgstr "במקרה של הפעלה מחדש של SABnzbd המסך ייעלם ב
msgid "WARNING:"
msgstr "אזהרה:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "שגיאה:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "משוך"
@@ -4693,6 +4713,14 @@ msgstr "יותר עמודות תור"
msgid "Extra history columns"
msgstr "יותר עמודות היסטוריה"
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "התקדמות"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "פעולות"
#: sabnzbd/skintext.py
msgid "page"
msgstr "דף"
@@ -4869,6 +4897,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr "מיין לפי % ירד <small>הכי הרבה&rarr;הכי מעט</small>"
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "מיין לפי גיל <small>החדש ביותר&larr;הישן ביותר</small>"
+93 -64
View File
@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
"Language-Team: Italian (https://app.transifex.com/sabnzbd/teams/111101/it/)\n"
@@ -122,7 +122,6 @@ msgstr "SABnzbd %s avviato"
msgid "SABnzbd shutdown finished"
msgstr "Arresto di SABnzbd terminato"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Segnale %s ricevuto, salvataggio e uscita in corso..."
@@ -270,15 +269,13 @@ msgstr "Il server richiede nome utente e password."
msgid "Connection Successful!"
msgstr "Connessione riuscita!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "Autenticazione fallita, controlla nome utente/password."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
"Troppe connessioni, si prega di mettere in pausa il download o riprovare più"
" tardi"
#: sabnzbd/api.py
msgid "Resolving address"
@@ -295,12 +292,12 @@ msgid "Default"
msgstr "Predefinito"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Disco pieno! Messa in pausa forzata"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Errore del disco durante la creazione del file %s"
@@ -607,20 +604,8 @@ msgid "Fatal error in Downloader"
msgstr "Errore fatale nel Downloader"
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "Troppe connessioni al server %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgid "Server %s reported: %s"
msgstr ""
"Accesso da troppi indirizzi IP diversi al server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Accesso fallito per il server %s [%s]"
#. Error message
#: sabnzbd/downloader.py
@@ -811,14 +796,23 @@ msgstr ""
"sparsi. Per dettagli e possibili soluzioni, vedi: "
"https://sabnzbd.org/wiki/advanced/direct-write"
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Connessione rifiutata da:"
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgstr "Connessione rifiutata con hostname \"%s\" da:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"Chiave API non corretta, Usa la chiave API da Config->Generale nel tuo "
"programma di terze parti:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr "Connessione rifiutata da:"
#: sabnzbd/interface.py
msgid ""
"API Key missing, please enter the api key from Config->General into your 3rd"
@@ -828,21 +822,17 @@ msgstr ""
"nel proprio programma di terze parti:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"Chiave API non corretta, Usa la chiave API da Config->Generale nel tuo "
"programma di terze parti:"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr "Utente ha effettuato l'accesso all'interfaccia web"
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr "Utente ha effettuato l'accesso"
msgid "Authentication failed, check username/password."
msgstr "Autenticazione fallita, controlla nome utente/password."
#. Warning message
#: sabnzbd/interface.py
@@ -905,14 +895,6 @@ msgstr ""
"La cartella della categoria non può essere una sottocartella della cartella "
"dei download temporanei."
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "ERRORE:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Indietro"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1375,6 +1357,11 @@ msgstr "Processo fallito"
msgid "Queue finished"
msgstr "Coda terminata"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr "Utente ha effettuato l'accesso"
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1619,6 +1606,23 @@ msgid ""
msgstr ""
"Se ricevi di nuovo questo messaggio di errore, prova un numero diverso.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1707,19 +1711,16 @@ msgstr ""
"Impossibile collegarsi alla porta %s su %s. Qualche altro software sta "
"usando la porta o SABnzbd è già in esecuzione."
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr "Impossibile avviare il browser, probabilmente non trovato"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Accesso negato"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "Errore %s: È necessario fornire un nome utente e una password validi."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2286,6 +2287,10 @@ msgstr "Host"
msgid "Cancel"
msgstr "Annulla"
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr "Accedi"
@@ -2875,10 +2880,6 @@ msgstr "Porta su cui SABnzbd dovrebbe essere in ascolto."
msgid "Web Interface Theme"
msgstr "Tema interfaccia web"
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr "Scegli un tema."
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "Nome utente SABnzbd"
@@ -3599,9 +3600,10 @@ msgstr ""
"processo."
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
"La coda verrà riordinata ogni 30 secondi se è selezionato % scaricato."
#: sabnzbd/skintext.py
msgid "Propagation delay"
@@ -3740,8 +3742,8 @@ msgid "Naming"
msgstr "Denominazione"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Quanto può essere scaricato questo mese (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4750,6 +4752,17 @@ msgstr "Spazio libero"
msgid "Temp Folder"
msgstr "Cartella temporanea"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Operazioni multiple"
@@ -4795,6 +4808,10 @@ msgstr ""
msgid "WARNING:"
msgstr "ATTENZIONE:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "ERRORE:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Recupera"
@@ -4831,6 +4848,14 @@ msgstr "Colonne extra della coda"
msgid "Extra history columns"
msgstr "Colonne extra della cronologia"
#: sabnzbd/skintext.py
msgid "Progress"
msgstr ""
#: sabnzbd/skintext.py
msgid "Actions"
msgstr ""
#: sabnzbd/skintext.py
msgid "page"
msgstr "pagina"
@@ -5007,6 +5032,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr "Ordina per % scaricato <small>Più&rarr;Meno</small>"
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Ordina per Età <small>Più vecchio&rarr;Più nuovo</small>"
+91 -58
View File
@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
"Language-Team: Norwegian Bokmål (https://app.transifex.com/sabnzbd/teams/111101/nb/)\n"
@@ -116,7 +116,6 @@ msgstr "SABnzbd %s startet"
msgid "SABnzbd shutdown finished"
msgstr "SABnzbd er nå avsluttet"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Signal %s mottatt, lagrer og avslutter..."
@@ -248,14 +247,13 @@ msgstr "Server krever brukernavn og passord."
msgid "Connection Successful!"
msgstr "Tilkobling lyktes!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "Godkjenning mislyktes, kontroller brukernavn og passord."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
"For mange tilkoblinger, sett nedlasting på pause eller prøv igjen senere"
#: sabnzbd/api.py
msgid "Resolving address"
@@ -272,12 +270,12 @@ msgid "Default"
msgstr "Standard"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Disken er full! Pauser..."
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Diskfeil under opprettelse av fil %s"
@@ -559,19 +557,9 @@ msgid "Fatal error in Downloader"
msgstr ""
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "For mange tilkoblinger til server %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgid "Server %s reported: %s"
msgstr ""
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Kunne ikke logge inn på server %s [%s]"
#. Error message
#: sabnzbd/downloader.py
msgid "Connecting %s@%s failed, message=%s"
@@ -750,11 +738,20 @@ msgid ""
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgid "Refused connection with hostname \"%s\" from:"
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"API-nøkkel er feil, bruk API-nøkkel fra Konfigurasjon->Generelt i ditt "
"tredjepartsprogram:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr ""
#: sabnzbd/interface.py
@@ -766,21 +763,17 @@ msgstr ""
"ditt tredjepartsprogram:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"API-nøkkel er feil, bruk API-nøkkel fra Konfigurasjon->Generelt i ditt "
"tredjepartsprogram:"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr "Bruker logget inn i webgrensesnitt"
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr "Bruker pålogget"
msgid "Authentication failed, check username/password."
msgstr "Godkjenning mislyktes, kontroller brukernavn og passord."
#. Warning message
#: sabnzbd/interface.py
@@ -841,14 +834,6 @@ msgid ""
"Category folder cannot be a subfolder of the Temporary Download Folder."
msgstr ""
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "FEIL:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Tilbake"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1296,6 +1281,11 @@ msgstr "Jobb mislyktes"
msgid "Queue finished"
msgstr "Køen er ferdig"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr "Bruker pålogget"
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1539,6 +1529,23 @@ msgid ""
"If you get this error message again, please try a different number.<br>"
msgstr "Prøv et annet nummer hvis du får denne feilmeldingen på nytt.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1625,19 +1632,16 @@ msgid ""
"SABnzbd is already running."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr "Kan ikke starte webserveren, ble sannsynlig vis ikke funnet"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Ingen tilgang"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "Feil %s: Du må oppgi et gyldig brukernavn og passord."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2204,6 +2208,10 @@ msgstr "Adresse"
msgid "Cancel"
msgstr "Avbryt"
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr "Logg på"
@@ -2784,10 +2792,6 @@ msgstr "Porten som SABnzbd skal bruke."
msgid "Web Interface Theme"
msgstr ""
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr ""
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "SABnzbd Brukernavn"
@@ -3457,7 +3461,9 @@ msgid "Automatically sort jobs in the queue when a new job is added."
msgstr ""
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
#: sabnzbd/skintext.py
@@ -3589,8 +3595,8 @@ msgid "Naming"
msgstr "Filnavn"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Hvor mye can lastes ned denne måneden (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4550,6 +4556,17 @@ msgstr "Ledig plass"
msgid "Temp Folder"
msgstr "Midlertidig Mappe"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Multioperasjoner"
@@ -4595,6 +4612,10 @@ msgstr ""
msgid "WARNING:"
msgstr "ADVARSEL:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "FEIL:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Hent"
@@ -4631,6 +4652,14 @@ msgstr ""
msgid "Extra history columns"
msgstr ""
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "Jobb"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Hendelser"
#: sabnzbd/skintext.py
msgid "page"
msgstr "side"
@@ -4799,6 +4828,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Sorter etter alder <small>Eldst&rarr;Ny</small>"
+93 -64
View File
@@ -8,7 +8,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
"Language-Team: Dutch (https://app.transifex.com/sabnzbd/teams/111101/nl/)\n"
@@ -123,7 +123,6 @@ msgstr "SABnzbd %s is gestart"
msgid "SABnzbd shutdown finished"
msgstr "SABnzbd is afgesloten"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Signaal %s ontvangen, opslaan en afsluiten..."
@@ -269,14 +268,13 @@ msgstr "Server heeft een gebruikersnaam en een wachtwoord nodig."
msgid "Connection Successful!"
msgstr "Succesvol verbonden!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "Inloggen mislukt, controleer gebruikersnaam en wachtwoord."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
"Te veel verbindingen, onderbreek het downloaden of probeer later nog eens."
#: sabnzbd/api.py
msgid "Resolving address"
@@ -293,12 +291,12 @@ msgid "Default"
msgstr "Standaard"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Schijf is vol; gedwongen pauze"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Schrijffout bij opslaan van bestand %s"
@@ -607,20 +605,8 @@ msgid "Fatal error in Downloader"
msgstr "Onherstelbare fout in de Downloader"
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "Te veel verbindingen met server %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgid "Server %s reported: %s"
msgstr ""
"Teveel verschillende IP-adressen probeerde in te loggen op server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Aanmelden bij server %s mislukt [%s]"
#. Error message
#: sabnzbd/downloader.py
@@ -813,14 +799,23 @@ msgstr ""
"ondersteunt. Zie voor details en mogelijke oplossingen: "
"https://sabnzbd.org/wiki/advanced/direct-write"
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Verbinding geweigerd van: "
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgstr "Verbinding met hostnaam \"%s\" geweigerd van:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"API-sleutel incorrect; vul de API-sleutel van 'Configuratie' => 'Algemeen' "
"in bij het externe programma:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr "Verbinding geweigerd van: "
#: sabnzbd/interface.py
msgid ""
"API Key missing, please enter the api key from Config->General into your 3rd"
@@ -830,21 +825,17 @@ msgstr ""
"in bij het externe programma:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"API-sleutel incorrect; vul de API-sleutel van 'Configuratie' => 'Algemeen' "
"in bij het externe programma:"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr "Gebruiker heeft ingelogd"
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr "Gebruiker ingelogd"
msgid "Authentication failed, check username/password."
msgstr "Inloggen mislukt, controleer gebruikersnaam en wachtwoord."
#. Warning message
#: sabnzbd/interface.py
@@ -907,14 +898,6 @@ msgstr ""
"Een Categorie specifieke map mag niet een map in de Tijdelijke download map "
"zijn."
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "FOUT:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Terug"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1378,6 +1361,11 @@ msgstr "Download mislukt"
msgid "Queue finished"
msgstr "Wachtrij voltooid"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr "Gebruiker ingelogd"
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1621,6 +1609,23 @@ msgid ""
"If you get this error message again, please try a different number.<br>"
msgstr "Als je dit bericht weer krijgt, probeer dan een ander nummer.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1709,19 +1714,16 @@ msgstr ""
"Kan niet binden aan poort %s van %s. Andere software gebruikt deze poort of "
"SABnzbd is al actief."
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr "Kan de web-browser niet starten, geen gevonden"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Toegang geweigerd"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "Fout %s: Je moet een geldige gebruikersnaam en wachtwoord invullen."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2289,6 +2291,10 @@ msgstr "Server"
msgid "Cancel"
msgstr "Annuleren"
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr "Aanmelden"
@@ -2877,10 +2883,6 @@ msgstr "Poort waar op SABnzbd luistert."
msgid "Web Interface Theme"
msgstr "Webinterface Stijl"
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr "Kies een stijl voor de webinterface."
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "Gebruikersnaam"
@@ -3600,10 +3602,10 @@ msgstr ""
"wordt toegevoegd"
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
"De wachtrij wordt elke 30 seconden opnieuw gesorteerd als de optie % "
"gedownload is gekozen."
#: sabnzbd/skintext.py
msgid "Propagation delay"
@@ -3742,8 +3744,8 @@ msgid "Naming"
msgstr "Naamgeving"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Hoeval mag deze maand worden gedownload (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4750,6 +4752,17 @@ msgstr "Vrije ruimte"
msgid "Temp Folder"
msgstr "Tijdelijke map"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Meervoudige bewerking"
@@ -4794,6 +4807,10 @@ msgstr "Wanneer SABnzbd opnieuw is gestart, gaat dit venster vanzelf weg!"
msgid "WARNING:"
msgstr "WAARSCHUWING:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "FOUT:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Ophalen"
@@ -4830,6 +4847,14 @@ msgstr "Extra kolommen aan wachtrij toevoegen"
msgid "Extra history columns"
msgstr "Extra kolommen aan geschiedenis toevoegen"
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "Voortgang"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Acties"
#: sabnzbd/skintext.py
msgid "page"
msgstr "Pagina"
@@ -5007,6 +5032,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr "Sorteer Op % Gedownload <small>Meest&rarr;Minst</small>"
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Sorteer op Leeftijd <small>Oud&rarr;Nieuw</small>"
+91 -59
View File
@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
"Language-Team: Polish (https://app.transifex.com/sabnzbd/teams/111101/pl/)\n"
@@ -114,7 +114,6 @@ msgstr "Uruchomiono SABnzbd %s"
msgid "SABnzbd shutdown finished"
msgstr "SABnzbd został wyłączony"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Odebrano sygnał %s, zapisywanie i zamykanie programu..."
@@ -246,15 +245,13 @@ msgstr "Serwer wymaga podania nazwy użytkownika i hasła."
msgid "Connection Successful!"
msgstr "Połączenie udane!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "Błąd połączenia, sprawdź nazwę użytkownika i hasło."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
"Zbyt wiele połączeń, proszę wstrzymać pobieranie lub spróbować ponownie "
"później"
#: sabnzbd/api.py
msgid "Resolving address"
@@ -271,12 +268,12 @@ msgid "Default"
msgstr "Domyślne"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Dysk pełny! Wstrzymuję pobieranie"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Błąd dysku podczas tworzenia pliku %s"
@@ -560,19 +557,9 @@ msgid "Fatal error in Downloader"
msgstr ""
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "Zbyt wiele połączeń do serwera %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgid "Server %s reported: %s"
msgstr ""
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Błąd logowania do serwera %s [%s]"
#. Error message
#: sabnzbd/downloader.py
msgid "Connecting %s@%s failed, message=%s"
@@ -753,11 +740,20 @@ msgid ""
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgid "Refused connection with hostname \"%s\" from:"
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"Klucz API jest nieprawidłowy, użyj klucza API z sekcji Konfiguracja->Ogólne "
"w zewnętrznym programie:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr ""
#: sabnzbd/interface.py
@@ -769,21 +765,17 @@ msgstr ""
"do zewnętrznego programu:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"Klucz API jest nieprawidłowy, użyj klucza API z sekcji Konfiguracja->Ogólne "
"w zewnętrznym programie:"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr ""
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr ""
msgid "Authentication failed, check username/password."
msgstr "Błąd połączenia, sprawdź nazwę użytkownika i hasło."
#. Warning message
#: sabnzbd/interface.py
@@ -844,14 +836,6 @@ msgid ""
"Category folder cannot be a subfolder of the Temporary Download Folder."
msgstr ""
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "BŁĄD:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Powrót"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1301,6 +1285,11 @@ msgstr "Zadanie nie powiodło się"
msgid "Queue finished"
msgstr "Kolejka ukończona"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr ""
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1545,6 +1534,23 @@ msgid ""
msgstr ""
"Jeśli ponownie otrzymasz ten sam błąd, spróbuj zmienić numer portu.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1631,20 +1637,17 @@ msgid ""
"SABnzbd is already running."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr ""
"Nie można uruchomić przeglądarki, prawdopodobnie nie została znaleziona"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Brak dostępu"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "Błąd %s: należy podać prawidłową nazwę użytkownika i hasło."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2213,6 +2216,10 @@ msgstr "Host"
msgid "Cancel"
msgstr "Anuluj"
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr ""
@@ -2792,10 +2799,6 @@ msgstr "Port, na którym ma nasłuchiwać SABnzbd"
msgid "Web Interface Theme"
msgstr ""
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr ""
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "Użytkownik SABnzbd"
@@ -3468,7 +3471,9 @@ msgid "Automatically sort jobs in the queue when a new job is added."
msgstr ""
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
#: sabnzbd/skintext.py
@@ -3600,8 +3605,8 @@ msgid "Naming"
msgstr "Nazwy"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Ile danych można pobrać w miesiącu (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4562,6 +4567,17 @@ msgstr "Wolne miejsce"
msgid "Temp Folder"
msgstr "Folder tymczasowy"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Operacje na wielu"
@@ -4607,6 +4623,10 @@ msgstr ""
msgid "WARNING:"
msgstr "UWAGA:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "BŁĄD:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Pobierz"
@@ -4643,6 +4663,14 @@ msgstr ""
msgid "Extra history columns"
msgstr ""
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "Postęp"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Działania"
#: sabnzbd/skintext.py
msgid "page"
msgstr "strona"
@@ -4811,6 +4839,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Sortuj według wieku <small>Najstarsze&rarr;Najnowsze</small>"
+91 -59
View File
@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
"Language-Team: Portuguese (Brazil) (https://app.transifex.com/sabnzbd/teams/111101/pt_BR/)\n"
@@ -119,7 +119,6 @@ msgstr "SABnzbd %s iniciado"
msgid "SABnzbd shutdown finished"
msgstr "Encerramento do SABnzbd concluído"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Sinal %s encontrado. Salvando e saindo..."
@@ -252,15 +251,13 @@ msgstr "Servidor requer usuário e senha."
msgid "Connection Successful!"
msgstr "Conexão com Sucesso!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "Falha de autenticação, verifique usuário / senha."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
"Excesso de conexões, por favor pause o download ou tente novamente mais "
"tarde"
#: sabnzbd/api.py
msgid "Resolving address"
@@ -277,12 +274,12 @@ msgid "Default"
msgstr "Padrão"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Disco cheio! Forçando Pausa"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Erro de disco na criação do arquivo %s"
@@ -574,19 +571,9 @@ msgid "Fatal error in Downloader"
msgstr ""
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "Excesso de conexões ao servidor %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgid "Server %s reported: %s"
msgstr ""
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Falha de logon ao servidor %s [%s]"
#. Error message
#: sabnzbd/downloader.py
msgid "Connecting %s@%s failed, message=%s"
@@ -765,11 +752,20 @@ msgid ""
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgid "Refused connection with hostname \"%s\" from:"
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"Chave de API incorreta. Use a chave de API de Configuração->Geral em seu "
"programa de terceiros:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr ""
#: sabnzbd/interface.py
@@ -781,21 +777,17 @@ msgstr ""
"Configuração->Geral em seu programa de terceiros:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"Chave de API incorreta. Use a chave de API de Configuração->Geral em seu "
"programa de terceiros:"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr ""
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr ""
msgid "Authentication failed, check username/password."
msgstr "Falha de autenticação, verifique usuário / senha."
#. Warning message
#: sabnzbd/interface.py
@@ -856,14 +848,6 @@ msgid ""
"Category folder cannot be a subfolder of the Temporary Download Folder."
msgstr ""
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "ERRO:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Voltar"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1310,6 +1294,11 @@ msgstr "Tarefa com falha"
msgid "Queue finished"
msgstr "Fila concluída"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr ""
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1555,6 +1544,23 @@ msgstr ""
"Se você receber esta mensagem de erro outra vez, tente um número "
"diferente.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1641,19 +1647,16 @@ msgid ""
"SABnzbd is already running."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr "Não é possível iniciar o navegador. Provavelmente não foi encontrado"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Acesso negado"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "Erro %s: Você precisa fornecer um nome de usuário e senha válidos."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2224,6 +2227,10 @@ msgstr "Host"
msgid "Cancel"
msgstr "Cancelar"
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr ""
@@ -2803,10 +2810,6 @@ msgstr "Porta onde o SABnzbd será ativado."
msgid "Web Interface Theme"
msgstr ""
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr ""
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "Usuário do SABnzbd"
@@ -3480,7 +3483,9 @@ msgid "Automatically sort jobs in the queue when a new job is added."
msgstr ""
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
#: sabnzbd/skintext.py
@@ -3612,8 +3617,8 @@ msgid "Naming"
msgstr "Nomeando"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Quanto pode ser baixado neste mês (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4573,6 +4578,17 @@ msgstr "Espaço Disponível"
msgid "Temp Folder"
msgstr "Pasta temporária"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Multi-Operações"
@@ -4618,6 +4634,10 @@ msgstr ""
msgid "WARNING:"
msgstr "AVISO:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "ERRO:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Obter"
@@ -4654,6 +4674,14 @@ msgstr ""
msgid "Extra history columns"
msgstr ""
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "Progresso"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Ações"
#: sabnzbd/skintext.py
msgid "page"
msgstr "página"
@@ -4822,6 +4850,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Ordenar por Idade <small>Mais antigo&rarr;Mais novo</small>"
+93 -61
View File
@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
"Language-Team: Romanian (https://app.transifex.com/sabnzbd/teams/111101/ro/)\n"
@@ -121,7 +121,6 @@ msgstr "SABnzbd %s pornit"
msgid "SABnzbd shutdown finished"
msgstr "Închidere SABnzbd terminată"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Semnal %s prins, salvez şi ies..."
@@ -256,15 +255,13 @@ msgstr "Serverul necesită nume utilizator şi parolă"
msgid "Connection Successful!"
msgstr "Conexiune Reuşită!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "Autentificare nereuşită, verifică nume utilizator/parolă."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
"Prea multe conexiuni, vă rugăm să întrerupeţi descărcarea sau să încercaţi "
"din nou mai târziu"
#: sabnzbd/api.py
msgid "Resolving address"
@@ -281,12 +278,12 @@ msgid "Default"
msgstr "Implicit"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Disc plin! Pauză Forţată"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Eroare disc la crearea fişierului %s"
@@ -582,19 +579,9 @@ msgid "Fatal error in Downloader"
msgstr ""
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "Prea multe conexiuni la serverul %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgid "Server %s reported: %s"
msgstr ""
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Autentificare nereuşită la serverul %s [%s]"
#. Error message
#: sabnzbd/downloader.py
msgid "Connecting %s@%s failed, message=%s"
@@ -772,14 +759,23 @@ msgid ""
"https://sabnzbd.org/wiki/advanced/direct-write"
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgstr "Conectare refuzată cu gazda „%s” de la:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"Cheie API incorectă, Folosiţi cheia api din Configurare->General în "
"programul dumneavoastră terţ:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr ""
#: sabnzbd/interface.py
msgid ""
"API Key missing, please enter the api key from Config->General into your 3rd"
@@ -789,21 +785,17 @@ msgstr ""
"Configurare->General în programul dumneavoastră terţ"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"Cheie API incorectă, Folosiţi cheia api din Configurare->General în "
"programul dumneavoastră terţ:"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr "Utilizatorul s-a autentificat în interfața web"
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr "Utilizator logat"
msgid "Authentication failed, check username/password."
msgstr "Autentificare nereuşită, verifică nume utilizator/parolă."
#. Warning message
#: sabnzbd/interface.py
@@ -866,14 +858,6 @@ msgstr ""
"Directorul de categorii nu poate fi un subdirector al directorului de "
"descărcări temporare."
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "EROARE:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Înapoi"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1328,6 +1312,11 @@ msgstr "Sarcină eșuată"
msgid "Queue finished"
msgstr "Coadă finalizată"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr "Utilizator logat"
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1573,6 +1562,23 @@ msgstr ""
"Dacă primiţi acest mesaj de eroare din nou, vă rugăm să încercaţi un alt "
"număr. <br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1661,19 +1667,16 @@ msgstr ""
"Nu pot rezerva portul %s pe %s. Alt software utilizează portul sau SABnzbs "
"rulează deja."
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr "Nu pot porni navigatorul web, probabil nu a fost găsit"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Acces interzis"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "Eroare %s: Trebuie să furnizaţi un nume utilizator şi parolă valid"
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2242,6 +2245,10 @@ msgstr "Gazdă"
msgid "Cancel"
msgstr "Anulează"
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr "Autentificare"
@@ -2824,10 +2831,6 @@ msgstr "Portul pe care SABnzbd îl va asculta."
msgid "Web Interface Theme"
msgstr ""
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr ""
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "Nume Utilizator SABnzbd"
@@ -3497,7 +3500,9 @@ msgid "Automatically sort jobs in the queue when a new job is added."
msgstr ""
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
#: sabnzbd/skintext.py
@@ -3631,8 +3636,8 @@ msgid "Naming"
msgstr "Redenumire"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Cât de mult poate fi descărcat în acestă lună (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4593,6 +4598,17 @@ msgstr "Spațiu liber"
msgid "Temp Folder"
msgstr "Dosar Temporar"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Operaţii-Multiple"
@@ -4637,6 +4653,10 @@ msgstr "În cazul repornirii SABnzbd acest ecran va dispărea în mod automat!"
msgid "WARNING:"
msgstr "ATENŢIE:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "EROARE:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Descarcă"
@@ -4673,6 +4693,14 @@ msgstr ""
msgid "Extra history columns"
msgstr ""
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "Progres"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Acțiuni"
#: sabnzbd/skintext.py
msgid "page"
msgstr "pagină"
@@ -4843,6 +4871,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Sortează după Vârstă <small>Cel mai Vechi&rarr;Cel mai Nou</small>"
+91 -59
View File
@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
"Language-Team: Russian (https://app.transifex.com/sabnzbd/teams/111101/ru/)\n"
@@ -119,7 +119,6 @@ msgstr ""
msgid "SABnzbd shutdown finished"
msgstr "Завершение работы SABnzbd закончено"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Получен сигнал %s. Выполняется сохранение и выход..."
@@ -247,15 +246,13 @@ msgstr "Для сервера требуется имя пользователя
msgid "Connection Successful!"
msgstr "Подключение установлено!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "Ошибка проверки подлинности. Проверьте имя и пароль."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
"Слишком много подключений. Приостановите загрузку или повторите попытку "
"позже"
#: sabnzbd/api.py
msgid "Resolving address"
@@ -272,12 +269,12 @@ msgid "Default"
msgstr "по умолчанию"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "На диске нет места Принудительная приостановка"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Ошибка диска при создании файла %s"
@@ -559,19 +556,9 @@ msgid "Fatal error in Downloader"
msgstr ""
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgid "Server %s reported: %s"
msgstr ""
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgstr ""
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Ошибка входа на сервер %s [%s]"
#. Error message
#: sabnzbd/downloader.py
msgid "Connecting %s@%s failed, message=%s"
@@ -750,11 +737,20 @@ msgid ""
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgid "Refused connection with hostname \"%s\" from:"
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"Неправильный ключ API. Используйте в сторонней программе ключ API из раздела"
" «Настройка -> Общие»:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr ""
#: sabnzbd/interface.py
@@ -766,21 +762,17 @@ msgstr ""
"«Настройка -> Общие»:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"Неправильный ключ API. Используйте в сторонней программе ключ API из раздела"
" «Настройка -> Общие»:"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr ""
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr ""
msgid "Authentication failed, check username/password."
msgstr "Ошибка проверки подлинности. Проверьте имя и пароль."
#. Warning message
#: sabnzbd/interface.py
@@ -841,14 +833,6 @@ msgid ""
"Category folder cannot be a subfolder of the Temporary Download Folder."
msgstr ""
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "ОШИБКА"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Назад"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1297,6 +1281,11 @@ msgstr ""
msgid "Queue finished"
msgstr ""
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr ""
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1542,6 +1531,23 @@ msgstr ""
"Если снова появляется это сообщение об ошибке, попробуйте указать другой "
"номер порта."
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1628,19 +1634,16 @@ msgid ""
"SABnzbd is already running."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr "Не удаётся запустить браузер. Возможно, он не было найден"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Доступ запрещён"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "Ошибка %s: укажите действительное имя пользователя и пароль."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2207,6 +2210,10 @@ msgstr "Адрес"
msgid "Cancel"
msgstr ""
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr ""
@@ -2786,10 +2793,6 @@ msgstr "Порт, по которому будет доступна служба
msgid "Web Interface Theme"
msgstr ""
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr ""
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "Имя пользователя SABnzbd"
@@ -3462,7 +3465,9 @@ msgid "Automatically sort jobs in the queue when a new job is added."
msgstr ""
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
#: sabnzbd/skintext.py
@@ -3594,8 +3599,8 @@ msgid "Naming"
msgstr "Именование"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Объем, который можно загрузить в месяц (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4560,6 +4565,17 @@ msgstr "свободно на диске"
msgid "Temp Folder"
msgstr ""
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Пакетные операции"
@@ -4604,6 +4620,10 @@ msgstr ""
msgid "WARNING:"
msgstr "ПРЕДУПРЕЖДЕНИЕ"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "ОШИБКА"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Загрузить"
@@ -4640,6 +4660,14 @@ msgstr ""
msgid "Extra history columns"
msgstr ""
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "Ход выполнения"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Действия"
#: sabnzbd/skintext.py
msgid "page"
msgstr "стр."
@@ -4808,6 +4836,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Сортировать по возрасту <small>от старых к новым</small>"
+91 -57
View File
@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
"Language-Team: Serbian (https://app.transifex.com/sabnzbd/teams/111101/sr/)\n"
@@ -116,7 +116,6 @@ msgstr "SABnzbd %s покренут"
msgid "SABnzbd shutdown finished"
msgstr "Гашење SABnzbd је завршено"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Signal %s primljen, snimanje i napuštanje..."
@@ -245,13 +244,13 @@ msgstr "Серверу су потребни име и лозинка."
msgid "Connection Successful!"
msgstr "Успешно привезивање!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "Аутентификација погрешна, проверити име/лозинку."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgstr "Превише конекција, паузирајте преузимање или поновите касније"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
#: sabnzbd/api.py
msgid "Resolving address"
@@ -268,12 +267,12 @@ msgid "Default"
msgstr "Подразумевано"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Disk je pun! Tera Pause"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Greška na disku prilikom kreiranja datoteke %s"
@@ -556,19 +555,9 @@ msgid "Fatal error in Downloader"
msgstr ""
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "Previše konekcija ka serveru %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgid "Server %s reported: %s"
msgstr ""
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Неуспешно пријављивање на сервер %s [%s]"
#. Error message
#: sabnzbd/downloader.py
msgid "Connecting %s@%s failed, message=%s"
@@ -747,11 +736,19 @@ msgid ""
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgid "Refused connection with hostname \"%s\" from:"
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"API кључ је погрешан, унети у спољни програм API кључ из Подешавања->Опште:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr ""
#: sabnzbd/interface.py
@@ -762,20 +759,17 @@ msgstr ""
"API кључ недостаје, унети у спољни програм API кључ из Подешавање->Опште:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"API кључ је погрешан, унети у спољни програм API кључ из Подешавања->Опште:"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr ""
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr ""
msgid "Authentication failed, check username/password."
msgstr "Аутентификација погрешна, проверити име/лозинку."
#. Warning message
#: sabnzbd/interface.py
@@ -836,14 +830,6 @@ msgid ""
"Category folder cannot be a subfolder of the Temporary Download Folder."
msgstr ""
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "ГРЕШКА:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Назад"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1291,6 +1277,11 @@ msgstr "Неуспешан рад"
msgid "Queue finished"
msgstr "Ред завршен"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr ""
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1534,6 +1525,23 @@ msgid ""
"If you get this error message again, please try a different number.<br>"
msgstr "Ако опет имате ову грешку, покушајте други број.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1620,19 +1628,16 @@ msgid ""
"SABnzbd is already running."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr "Немогуће је покренути претраживач, вероватно није нађен"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Приступ одбијен"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "Грешка %s: Требате да унесете важеће име/лозинку."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2199,6 +2204,10 @@ msgstr "Хост"
msgid "Cancel"
msgstr "Откажи"
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr ""
@@ -2776,10 +2785,6 @@ msgstr "Порт на који SABnzbd чека везе."
msgid "Web Interface Theme"
msgstr ""
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr ""
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "Корисничко име SABnzbd-а"
@@ -3446,7 +3451,9 @@ msgid "Automatically sort jobs in the queue when a new job is added."
msgstr ""
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
#: sabnzbd/skintext.py
@@ -3576,8 +3583,8 @@ msgid "Naming"
msgstr "Именовање"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Колико може да се преузме овог месеца (К/М/Г)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4535,6 +4542,17 @@ msgstr "Слободан простор"
msgid "Temp Folder"
msgstr "Привремено"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Мулти-операције"
@@ -4580,6 +4598,10 @@ msgstr ""
msgid "WARNING:"
msgstr "ПАЖЊА:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "ГРЕШКА:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Преузми"
@@ -4616,6 +4638,14 @@ msgstr ""
msgid "Extra history columns"
msgstr ""
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "Напредак"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Акције"
#: sabnzbd/skintext.py
msgid "page"
msgstr "страни"
@@ -4784,6 +4814,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Среди по старост <small>Старије&rarr;Новије</small>"
+92 -58
View File
@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2026\n"
"Language-Team: Swedish (https://app.transifex.com/sabnzbd/teams/111101/sv/)\n"
@@ -116,7 +116,6 @@ msgstr "SABnzbd %s startad"
msgid "SABnzbd shutdown finished"
msgstr "SABnzbd nedstängning utförd."
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "Signal %s mottagen, sparar och stänger..."
@@ -245,13 +244,13 @@ msgstr "Servern kräver användarnamn och lösenord."
msgid "Connection Successful!"
msgstr "Anslutning lyckades!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr "Autentisering misslyckades, kontrollera användarnamn och lösenord."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgstr "För många anslutningar, pausa en nedladdning eller försök igen senare"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
#: sabnzbd/api.py
msgid "Resolving address"
@@ -268,12 +267,12 @@ msgid "Default"
msgstr "Standard"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Disken är full! Pausar..."
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "Diskfel vid skapande av fil %s"
@@ -556,19 +555,9 @@ msgid "Fatal error in Downloader"
msgstr ""
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "För många anslutningar till servern %s [%s]"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgid "Server %s reported: %s"
msgstr ""
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "Det gick inte att logga in på server %s [%s]"
#. Error message
#: sabnzbd/downloader.py
msgid "Connecting %s@%s failed, message=%s"
@@ -747,11 +736,20 @@ msgid ""
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgid "Refused connection with hostname \"%s\" from:"
msgstr ""
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"API-nyckel felaktig, använd api-nyckeln från Konfiguration-> Allmänt i ditt "
"tredjepartsprogram:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr ""
#: sabnzbd/interface.py
@@ -763,21 +761,17 @@ msgstr ""
"tredjepartsprogram:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr ""
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"API-nyckel felaktig, använd api-nyckeln från Konfiguration-> Allmänt i ditt "
"tredjepartsprogram:"
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr ""
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr ""
msgid "Authentication failed, check username/password."
msgstr "Autentisering misslyckades, kontrollera användarnamn och lösenord."
#. Warning message
#: sabnzbd/interface.py
@@ -838,14 +832,6 @@ msgid ""
"Category folder cannot be a subfolder of the Temporary Download Folder."
msgstr ""
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "FEL:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Bakåt"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1295,6 +1281,11 @@ msgstr "Jobb misslyckades"
msgid "Queue finished"
msgstr "Kön färdig"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr ""
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1540,6 +1531,23 @@ msgstr ""
"Om du får detta felmeddelande igen, var vänlig försök med en annan "
"siffra.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1626,19 +1634,16 @@ msgid ""
"SABnzbd is already running."
msgstr ""
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr "Kan inte starta webbläsaren, hittades troligtvis inte"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Åtkomst nekades"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "Error %s: Du måste ange ett giltigt användarnamn och lösenord."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -2205,6 +2210,10 @@ msgstr "Adress"
msgid "Cancel"
msgstr "Avbryt"
#: sabnzbd/skintext.py
msgid "Close"
msgstr ""
#: sabnzbd/skintext.py
msgid "Log in"
msgstr ""
@@ -2784,10 +2793,6 @@ msgstr "Port som SABnzbd ska lyssna på."
msgid "Web Interface Theme"
msgstr ""
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr ""
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "SABnzbd Användarnamn"
@@ -3456,7 +3461,9 @@ msgid "Automatically sort jobs in the queue when a new job is added."
msgstr ""
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
#: sabnzbd/skintext.py
@@ -3588,8 +3595,8 @@ msgid "Naming"
msgstr "Döpning"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Hur mycket kan laddas ner denna månad (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr ""
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4548,6 +4555,17 @@ msgstr "Ledigt diskutrymme"
msgid "Temp Folder"
msgstr "Temporär Mapp"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr ""
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Multi-operationer"
@@ -4592,6 +4610,10 @@ msgstr "Om SABnzbd startar om kommer denna skärm att försvinna automatiskt!"
msgid "WARNING:"
msgstr "VARNING:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "FEL:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Hämta"
@@ -4628,6 +4650,14 @@ msgstr ""
msgid "Extra history columns"
msgstr ""
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "Förlopp"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Åtgärder"
#: sabnzbd/skintext.py
msgid "page"
msgstr "sida"
@@ -4796,6 +4826,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr ""
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Sortera efter ålder <small>Äldst&rarr;Nyast</small>"
+116 -68
View File
@@ -8,7 +8,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-5.1.0\n"
"Project-Id-Version: SABnzbd-5.2.0\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: mauron, 2026\n"
"Language-Team: Turkish (https://app.transifex.com/sabnzbd/teams/111101/tr/)\n"
@@ -123,7 +123,6 @@ msgstr "SABnzbd %s başlatıldı"
msgid "SABnzbd shutdown finished"
msgstr "SABnzbd kapatılması tamamlandı"
#. Warning message
#: sabnzbd/__init__.py
msgid "Signal %s caught, saving and exiting..."
msgstr "%s sinyali yakalandı, kaydediliyor ve çıkılıyor..."
@@ -269,16 +268,17 @@ msgstr "Sunucu kullanıcı ismi ve parola gerektiriyor."
msgid "Connection Successful!"
msgstr "Bağlantı Başarılı!"
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Authentication failed, check username/password."
msgstr ""
"Kimlik doğrulaması başarısız oldu, kullanıcı ismi/parola kontrolü yapın."
#. Warning message
#: sabnzbd/api.py
msgid "Too many connections, please pause downloading or try again later"
msgid ""
"Server %s took %d ms to respond. On high-latency connections, increasing "
"'Articles per request' to a value between 5 and 10 can improve download "
"speed. See: https://sabnzbd.org/wiki/advanced/nntp-pipelining"
msgstr ""
"Çok fazla bağlantı, lütfen indirmeyi duraklatın veya daha sonra tekrar "
"deneyin"
"%s sunucusunun cevap vermesi %d ms sürdü. Yüksek gecikmeli bağlantılarda, "
"'talep başı makale' değerini 5 ila 10 olarak ayarlamak indirme hızını "
"iyileştirebilir. Şu sayfaya bakın: https://sabnzbd.org/wiki/advanced/nntp-"
"pipelining"
#: sabnzbd/api.py
msgid "Resolving address"
@@ -295,12 +295,12 @@ msgid "Default"
msgstr "Varsayılan"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk full! Forcing Pause"
msgstr "Disk dolu! Duraklatma Zorlanıyor"
#. Error message
#: sabnzbd/assembler.py
#: sabnzbd/assembler.py, sabnzbd/decoder.py
msgid "Disk error on creating file %s"
msgstr "%s dosyasının oluşturulmasında disk hatası"
@@ -603,20 +603,8 @@ msgid "Fatal error in Downloader"
msgstr "İndirici'de ölümcül hata"
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
msgstr "%s [%s] sunucusuna çok fazla bağlantı"
#: sabnzbd/downloader.py
msgid ""
"Login from too many different IP addresses to server %s [%s] - "
"https://sabnzbd.org/multiple-adresses"
msgstr ""
"%s [%s] sunucusuna çok fazla farklı IP adreslerinden oturum açılışı yapıldı "
"- https://sabnzbd.org/multiple-adresses"
#: sabnzbd/downloader.py
msgid "Failed login for server %s [%s]"
msgstr "%s [%s] sunucusunda oturum açılışı başarısız oldu"
msgid "Server %s reported: %s"
msgstr "%s sunucusu şunu bildirdi: %s"
#. Error message
#: sabnzbd/downloader.py
@@ -802,14 +790,23 @@ msgstr ""
"dışı bırakılmıştır. Ayrıntılar ve muhtemel çözümler için şu sayfaya bakın: "
"https://sabnzbd.org/wiki/advanced/direct-write"
#: sabnzbd/interface.py
msgid "Refused connection from:"
msgstr "Şuradan bağlantı reddedildi:"
#: sabnzbd/interface.py
msgid "Refused connection with hostname \"%s\" from:"
msgstr "Şuradan \"%s\" makine ismi ile bağlantı reddedildi:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgstr ""
"API anahtarı yanlış, 3. taraf programınızda Yapılandırma->Genel'den api "
"anahtarını kullanın:"
#. Warning message
#: sabnzbd/interface.py, sabnzbd/security.py
msgid "Refused connection from:"
msgstr "Şuradan bağlantı reddedildi:"
#: sabnzbd/interface.py
msgid ""
"API Key missing, please enter the api key from Config->General into your 3rd"
@@ -819,21 +816,19 @@ msgstr ""
"programınıza girin:"
#: sabnzbd/interface.py
msgid ""
"API Key incorrect, Use the api key from Config->General in your 3rd party "
"program:"
msgid "Too many failed login attempts, try again later."
msgstr "Çok fazla oturum açma teşebbüssü, daha sonra tekrar deneyin."
#. Warning message
#: sabnzbd/interface.py
msgid "Login attempt refused, too many failures from %s"
msgstr ""
"API anahtarı yanlış, 3. taraf programınızda Yapılandırma->Genel'den api "
"anahtarını kullanın:"
"Oturum açma teşebbüsü reddedildi, %s unsurundan çok fazla başarısız girişim."
#: sabnzbd/interface.py
msgid "User logged in to the web interface"
msgstr "Kullanıcı web arayüzünde oturum açtı"
#. Notification
#: sabnzbd/interface.py, sabnzbd/notifier.py
msgid "User logged in"
msgstr "Kullanıcı oturum açtı"
msgid "Authentication failed, check username/password."
msgstr ""
"Kimlik doğrulaması başarısız oldu, kullanıcı ismi/parola kontrolü yapın."
#. Warning message
#: sabnzbd/interface.py
@@ -894,14 +889,6 @@ msgid ""
"Category folder cannot be a subfolder of the Temporary Download Folder."
msgstr "Kategori dizini Geçici İndirme Dizini'nin bir alt dizini olamaz."
#: sabnzbd/interface.py, sabnzbd/skintext.py
msgid "ERROR:"
msgstr "HATA:"
#: sabnzbd/interface.py
msgid "Back"
msgstr "Geri"
#. Warning message
#: sabnzbd/internetspeed.py
msgid ""
@@ -1363,6 +1350,11 @@ msgstr "İş başarısız oldu"
msgid "Queue finished"
msgstr "Kuyruk bitti"
#. Notification
#: sabnzbd/notifier.py
msgid "User logged in"
msgstr "Kullanıcı oturum açtı"
#. Notification
#: sabnzbd/notifier.py
msgid "Other Messages"
@@ -1606,6 +1598,30 @@ msgid ""
"If you get this error message again, please try a different number.<br>"
msgstr "Bu hata mesajını tekrar alırsanız, lütfen başka bir sayı deneyin.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
" SABnzbd is not allowed to use port %s on %s.<br>\n"
" Low port numbers are reserved for privileged processes on most systems,\n"
" so the port itself is available but cannot be claimed.<br>\n"
" <br>\n"
" Either run SABnzbd with the privileges needed for that port, or restart it\n"
" with a port number of 1024 or higher."
msgstr ""
"\n"
"SABnzbd'nin %s bağlantı noktasını %s üzerinde kullanma izni yoktur. <br>\n"
"Düşük bağlantı noktaları, sistemlerin çoğunluğunda imtiyazlı süreçler için ayrılmıştır, yani bağlantı noktası mevcuttur ama talep edilemezler.<br>\n"
"<br>\n"
"Ya SABnzbd'yi bu bağlantı noktası için ihtiyaç duyulan izinlerle çalıştırın ya da onu 1024 veya daha yüksek bir bağlantı noktası sayısı ile tekrar başlatın."
#: sabnzbd/panic.py
msgid ""
"To keep using the low port, put a reverse proxy in front of SABnzbd "
"instead.<br>"
msgstr ""
"Düşük bağlantı noktasını kullanmaya devam etmek için bunun yerine "
"SABnzbd'nin önüne ters bir vekil sunucu koyun.<br>"
#: sabnzbd/panic.py
msgid ""
"\n"
@@ -1694,19 +1710,18 @@ msgstr ""
"%s bağlantı noktasına %s üzerinde bağlanılamıyor. Başka bir yazılım bağlantı"
" noktasını kullanıyor veya SABnzbd zaten çalışıyor."
#: sabnzbd/panic.py
msgid ""
"Not allowed to bind to port %s on %s. Low ports need elevated privileges."
msgstr ""
"%s bağlantı noktasına %s üzerinde bağlanma izni yoktur. Düşük bağlantı "
"noktaları yüksek izinler gerektirir."
#. Warning message
#: sabnzbd/panic.py
msgid "Cannot launch the browser, probably not found"
msgstr "Tarayıcı başlatılamıyor, muhtemelen bulunamadı"
#: sabnzbd/panic.py
msgid "Access denied"
msgstr "Erişim reddedildi"
#: sabnzbd/panic.py
msgid "Error %s: You need to provide a valid username and password."
msgstr "Hata %s: geçerli bir kullanıcı ismi ve parola sağlamanız gerekiyor."
#. Warning message
#: sabnzbd/postproc.py
msgid "Old queue detected, use Status->Repair to convert the queue"
@@ -1839,7 +1854,7 @@ msgstr "%s kaldırması başarısız oldu"
#: sabnzbd/postproc.py
msgid "Removed %s files with unwanted extensions"
msgstr ""
msgstr "İstemeyen uzantılı %s dosya kaldırıldı"
#. Error message
#: sabnzbd/powersup.py
@@ -2275,6 +2290,10 @@ msgstr "Makine"
msgid "Cancel"
msgstr "İptal"
#: sabnzbd/skintext.py
msgid "Close"
msgstr "Kapat"
#: sabnzbd/skintext.py
msgid "Log in"
msgstr "Oturum aç"
@@ -2865,10 +2884,6 @@ msgstr "SABnzbd'nin dinleyeceği bağlantı noktası (port)."
msgid "Web Interface Theme"
msgstr "Web Arayüz Teması"
#: sabnzbd/skintext.py
msgid "Choose a theme."
msgstr "Bir tema seçin."
#: sabnzbd/skintext.py
msgid "SABnzbd Username"
msgstr "SABnzbd Kullanıcı ismi"
@@ -3582,9 +3597,12 @@ msgid "Automatically sort jobs in the queue when a new job is added."
msgstr "Kuyruktaki işleri yeni bir iş eklendiğinde otomatik olarak sırala."
#: sabnzbd/skintext.py
msgid "The queue will resort every 30 seconds if % downloaded is selected."
msgid ""
"The queue will resort every 30 seconds if % downloaded or Remaining Size is "
"selected."
msgstr ""
"İndirme %'si seçildiyse, kuyruk her 30 saniyede bir tekrar sıralanacaktır."
"Eğer % indirildiyse veya Kalan Boyut seçildiyse kuyruk her 30 saniyede bir "
"tekrar sıralanacaktır."
#: sabnzbd/skintext.py
msgid "Propagation delay"
@@ -3724,8 +3742,8 @@ msgid "Naming"
msgstr "İsimlendirme"
#: sabnzbd/skintext.py
msgid "How much can be downloaded this month (K/M/G)"
msgstr "Bu ay ne kadar indirme yapılabileceği (K/M/G)"
msgid "How much can be downloaded this Quota period (K/M/G)"
msgstr "Bu kota süresinde ne kadar indirme yapılabileceği (K/M/G)"
#. Reset day of the download quota
#: sabnzbd/skintext.py
@@ -4733,6 +4751,20 @@ msgstr "Boş alan"
msgid "Temp Folder"
msgstr "Geçici Dizin"
#: sabnzbd/skintext.py
msgid "Clear search"
msgstr "Aramayı temizle"
#: sabnzbd/skintext.py
msgid ""
"Search by name, or refine with filters <code>cat:</code>, "
"<code>status:</code> and <code>priority:</code> (Queue). For example: "
"<code>my show cat:tv</code>"
msgstr ""
"İsimle arama yapın veya <code>kat:</code>, <code>durum:</code> ve "
"<code>öncelik</code> (Kuyruk) süzgeçleriyle aramayı daraltın. Mesela: "
"<code>benim programım kat:tv</code>"
#: sabnzbd/skintext.py
msgid "Multi-Operations"
msgstr "Çoklu-İşlemler"
@@ -4743,7 +4775,7 @@ msgstr "Bir aralık seçmek için Shift tuşunu basılı tutun"
#: sabnzbd/skintext.py
msgid "Select job"
msgstr ""
msgstr "İş seç"
#: sabnzbd/skintext.py
msgid "Check all"
@@ -4779,6 +4811,10 @@ msgstr ""
msgid "WARNING:"
msgstr "İKAZ:"
#: sabnzbd/skintext.py
msgid "ERROR:"
msgstr "HATA:"
#: sabnzbd/skintext.py
msgid "Fetch"
msgstr "Al"
@@ -4815,6 +4851,14 @@ msgstr "Ek kuyruk sütunları"
msgid "Extra history columns"
msgstr "Ek tarihçe sütunları"
#: sabnzbd/skintext.py
msgid "Progress"
msgstr "İlerleme"
#: sabnzbd/skintext.py
msgid "Actions"
msgstr "Eylemler"
#: sabnzbd/skintext.py
msgid "page"
msgstr "sayfa"
@@ -4992,6 +5036,10 @@ msgstr ""
msgid "Sort by % downloaded <small>Most&rarr;Least</small>"
msgstr "İndirilen % ile sırala <small>Azami&rarr;Asgari</small>"
#: sabnzbd/skintext.py
msgid "Sort by Remaining Size <small>Smallest&rarr;Largest</small>"
msgstr "Kalan Boyuta Göre Sırala <small>Asgari&rarr;Azami</small>"
#: sabnzbd/skintext.py
msgid "Sort by Age <small>Oldest&rarr;Newest</small>"
msgstr "Yaşa göre sırala <small>En eski&rarr;En yeni</small>"
Loaded 100 of 217 files, more files were not shown because too many files have changed in this diff. Show more