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.
* 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
* 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
* Label schedule time, enable, and delete controls
* Use ARIA label for schedule enable control
---------
Co-authored-by: coopa11y <coopa11y@users.noreply.github.com>
* 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>
* RSS age rule
* Support years (y) and months (mo) and do not approximate durations in seconds
* Better handling of entries with no age
* Formatting
* Allow >=, =>, <=, and =< aliases
* Implement feedback
* Fix existing issue with From SxxEyy in default row
* Test unitless ages
Updates the default number of connections from 8 to 16 in the server configuration and wizard UI templates. This change aims to improve performance for users who do not explicitly configure this setting.
Additionally, ensures the API server test function defaults to at least 1 connection when none is specified.
Relates to #3284
Refines margins, paddings, and element positioning across various components to improve visual harmony and alignment with the modernized interface design.
This modernizes the theming architecture by defining core colors as CSS variables,
allowing themes like 'Night' to override them concisely. This approach improves
maintainability and removes dynamic styling previously handled by JavaScript.
* Remove UI delays
* Everything using set_config, set_platform, or pyfakefs
* tmp_path
* Scroll to top seems unnecessary but make it wait until it's done
* Remove sleep from test_rss_basic_flow
* Remove sleeps from test_daemonizing
* Define pytest markers
* Reduce sleep in test_queue_repair
* Remove sleeps from clean_cache_dir
* Suppress failures to connect during startup
* Reduce cache sleeps
* Reduce sleeps checking app started
* Reduce sleep removing cache dir
* Include byte unit in quota strings
Fixes#2590
I expect to continue to iterate on some of the ideas in the comments
thereon, but this fixes the proximate issue mentioned in the issue.
This includes changes to the interface to properly interpret the new
strings:
- Remove the UI-based `B` designations as they are now tagged with
units from the api
- Let parseInt do its magic with string-y numbers plus units
- Expand parseInt for use in the checking whether quota is set
The display will be better in this `Glitter` case. This may well be
considered a breaking change for the API and not applied.
* Reduce computation slightly
No need to iterate over the evenly spaced unit sizes.
We can determine its magnitude quickly and convert it
into an index for our tags.
Avoiding the repeated divisons might also reduce error, but it is
unlikely to be noticeable.
* Drop trailing space when no units
The issue didn't expressly complain, but there is a trailing space when
all of the other unit information is empty. Might as well not include
it when it clearly will happen.
The use of `f-strings` might also simplify future maintenance.
* Better document to_units methodology
This addresses some code review concerns with respect to readability.
Frankly, having this much exposition in the comments might imply that
it's a lot less obvious than I thought at initial writing.
This also maps everything under `1024` directly to `0`. This avoids
concerns about potentially generating negative indices into the tags
tuple which would be surprising and wildly incorrect.