Compare commits

...

91 Commits
4.3.1 ... 4.3.3

Author SHA1 Message Date
Safihre
f24b3ced28 Set version to 4.3.3 2024-08-21 13:26:46 +02:00
Safihre
157dfc928d Merge branch '4.3.x' 2024-08-21 13:26:14 +02:00
Safihre
d10639542d Update text files for 4.3.3 2024-08-21 13:25:48 +02:00
Safihre
c0f0b7eb31 Add Docker to CPU label 2024-08-19 20:22:29 +02:00
Safihre
d6d70325db Small style fixes for the Config 2024-08-19 20:22:23 +02:00
Safihre
46954165d2 Update text files for 4.3.3RC2 2024-08-17 15:08:57 +02:00
Safihre
58e7d520bf increase_bad_articles_counter should be called before register_article 2024-08-17 15:08:03 +02:00
Safihre
a4f8040324 Prevent excessive newswrapper data buffer size
Closes #2895
2024-08-17 15:07:57 +02:00
Safihre
8d5cc9a3e6 Do not use article_queue when resetting newswrapper
Relates to #2866
2024-08-17 15:07:52 +02:00
jcfp
4592ce4d55 Remove pyfakefs workarounds and put its new apply_umask option to good use (#2922) 2024-08-17 15:07:47 +02:00
Safihre
b62b38b5af Update text files for 4.3.3RC1 2024-08-13 10:29:25 +02:00
renovate[bot]
14b1d4630c Update all dependencies 2024-08-13 10:16:28 +02:00
Safihre
621d586c2f Reduce timeouts during happyeyeballs and others 2024-08-09 10:01:21 +02:00
Safihre
4966f9c753 Update sabctools to 8.2.5 2024-08-09 09:42:57 +02:00
SABnzbd Automation
059d82f6f0 Update translatable texts
[skip ci]
2024-08-05 00:18:07 +00:00
renovate[bot]
bca41db6b7 Update all dependencies 2024-08-05 00:17:22 +00:00
renovate[bot]
613ba0b05f Update dependency setuptools to v72 2024-07-29 03:45:46 +00:00
renovate[bot]
5f3b03ed87 Update all dependencies 2024-07-29 02:12:43 +00:00
SABnzbd Automation
f6fe801000 Update translatable texts
[skip ci]
2024-07-28 16:31:44 +00:00
bt90
8ff34660d8 Add autocomplete attributes (#2916) 2024-07-28 10:31:03 -06:00
renovate[bot]
0c1b8dd60a Update all dependencies 2024-07-24 23:08:07 +00:00
SABnzbd Automation
8e8ee7a3ab Update translatable texts
[skip ci]
2024-07-24 22:11:38 +00:00
Safihre
9145a90e33 Update test_cert_gen for new cryptography default 2024-07-24 16:10:58 -06:00
Safihre
02b4a116dd Update AppData for 4.3.3 2024-07-16 00:06:21 +02:00
SABnzbd Automation
e504b288a2 Update translatable texts
[skip ci]
2024-07-15 22:05:36 +00:00
Safihre
5128f788f0 Update text files for 4.3.3Beta2 2024-07-16 00:02:42 +02:00
Sander
044fe7a26a fix when no connection (for example IPv6-test on IPv4-only connection) (#2908)
* fix when no connection (for example IPv6-test on IPv4-only connection)

* fix when no connection (for example IPv6-test on IPv4-only connection)

* make black happy ... hopefully

* make black happy ... hopefully ... linelength 120
2024-07-15 07:27:43 +02:00
renovate[bot]
4ed2565101 Update all dependencies 2024-07-15 03:56:19 +00:00
SABnzbd Automation
abbd77bac4 Update translatable texts
[skip ci]
2024-07-14 21:24:11 +00:00
Safihre
38c9a52e1d Add changes to web_host and web_port to ignored revs 2024-07-14 23:23:26 +02:00
Safihre
f89114ca7e Rename cherryhost and cherryport to web_host and web_port 2024-07-14 23:23:01 +02:00
Safihre
773d567eed Skip propagation delay calculation if delay is set to 0
Since OptionNumber doesn't allow empty values
2024-07-14 23:19:05 +02:00
Safihre
ee717b679e Set limits to number-input types that were missing them 2024-07-13 19:39:53 +02:00
Safihre
f50810fb58 Remove article from TryList when resetting article Queue
When we reset the Server's Article-queue, we should retry that article again on that server.
2024-07-10 20:48:06 +02:00
jcfp
08b1b20b34 fix filesystem permission test for pyfakefs 5.4.0+ (#2905) 2024-07-10 16:16:18 +02:00
SABnzbd Automation
edca79af83 Update translatable texts
[skip ci]
2024-07-08 13:11:04 +00:00
Safihre
dd5dcd0ec9 Update text files for 4.3.3Beta1 2024-07-08 15:10:22 +02:00
Safihre
820824e443 Disable failing test until #2883 is fixed 2024-07-08 13:47:01 +02:00
Safihre
4c2dfdee43 Correctly handle the difference between no category and Default
Closes #2902
2024-07-08 13:47:00 +02:00
Safihre
ece4437c3a General changes to sanitization functions 2024-07-08 13:46:59 +02:00
renovate[bot]
74daa15ce4 Update dependency certifi to v2024.7.4 (#2904)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-08 08:04:01 +02:00
renovate[bot]
4f81bc8a26 Update all dependencies (#2901)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-02 22:10:07 +02:00
jcfp
e77d15f75e don't bother looking up a public address if the local ipv6 is link-local (#2899) 2024-06-29 10:16:12 +02:00
Sander
8668852574 make WIN64 also true if on ARM64 (#2893)
Co-authored-by: sander <san.d.erjonkers+github@gmail.com>
2024-06-25 07:03:18 +02:00
renovate[bot]
7e944f393e Update winrt dependencies to v2.1.0 (#2891)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-24 15:29:58 +02:00
renovate[bot]
1646fbfd17 Update all dependencies (#2890)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-24 06:52:59 +02:00
Safihre
72b0521325 Correct crash in Notifications page
Closes #2887
2024-06-19 21:11:03 +02:00
renovate[bot]
8aa53fd43f Update all dependencies (#2882)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 14:22:03 +02:00
Safihre
aa67edb2d9 Fix macOS CI run by pinning older Python 3.12.3 version 2024-06-17 09:25:51 +02:00
SABnzbd Automation
0054b17f41 Update translatable texts
[skip ci]
2024-06-17 07:03:09 +00:00
Safihre
2af2cc7370 Add file version information to Windows installer
#2870
2024-06-17 09:02:29 +02:00
renovate[bot]
5aa7aafebb Update all dependencies 2024-06-10 01:14:35 +00:00
Safihre
3bd0f7c1e0 Experiment to improve idle job detection
No longer rely on just length of arrays, but use fast set-comparisons.
2024-06-09 22:23:55 +02:00
Safihre
9c8d21f6db Remove warning about AppRise
Closes #2875
2024-06-09 21:22:52 +02:00
SABnzbd Automation
4947effeb7 Update translatable texts
[skip ci]
2024-06-09 19:02:22 +00:00
Safihre
b8fd9e6e31 Introduce bool_conv and fix ambiguous JSON retry value in history queue 2024-06-09 21:01:32 +02:00
jcfp
2a02c93e4b Fix checkdir argument handling (#2873)
* fix checkdir argument handling

* housekeeping

* shut up black
2024-06-03 22:03:20 +02:00
SABnzbd Automation
a0ef520e06 Update translatable texts
[skip ci]
2024-06-03 02:05:42 +00:00
renovate[bot]
a9eb32eba6 Update all dependencies 2024-06-03 02:05:01 +00:00
SABnzbd Automation
592ef0e645 Update translatable texts
[skip ci]
2024-05-31 14:13:53 +00:00
Safihre
cce53ee058 Set version to 4.3.2 2024-05-31 16:13:02 +02:00
Safihre
93755aa6d8 Update sabctools to 8.3.3 2024-05-29 16:55:12 +02:00
Safihre
8a42abd1e7 Set version to 4.3.2 2024-05-29 16:38:23 +02:00
Safihre
41e5dfdf18 Merge branch '4.3.x' 2024-05-29 16:28:43 +02:00
SABnzbd Automation
b1d42c7c22 Update translatable texts
[skip ci]
2024-05-27 20:00:41 +00:00
Safihre
8286b7b830 Add pkg_resources.extern to hidden imports 2024-05-27 19:59:56 +00:00
renovate[bot]
fbaa3c0420 Update all dependencies 2024-05-27 19:59:56 +00:00
SABnzbd Automation
ba6c30cf24 Update translatable texts
[skip ci]
2024-05-23 08:24:29 +00:00
Safihre
3ce5679298 Update text files for 4.3.2RC2 2024-05-23 10:23:41 +02:00
jcfp
47e1d40943 set basic systemd hardening options (#2865) 2024-05-22 13:52:23 +02:00
Safihre
1687130107 Ignore shutdown exception in cheroot
Closes #2857
2024-05-22 10:20:09 +02:00
SABnzbd Automation
8e59146d60 Update translatable texts
[skip ci]
2024-05-20 00:41:49 +00:00
renovate[bot]
4b37d2772f Update all dependencies 2024-05-20 00:41:01 +00:00
thezoggy
ea9d690a90 Switch discord link to vanity link. Add binhex as docker maintainer entry (#2861) 2024-05-17 07:16:25 +02:00
Safihre
3a2e967a03 Add 4.3.2 to appdata 2024-05-16 21:45:00 +02:00
SABnzbd Automation
a2eb0cc2c3 Update translatable texts
[skip ci]
2024-05-16 19:44:14 +00:00
Safihre
8b9341023a Update text files for 4.3.2RC1 2024-05-16 21:39:42 +02:00
Safihre
54314c0198 Only remove Windows shortcuts on uninstall
Closes #2850
2024-05-16 21:32:53 +02:00
Safihre
b0e4c4c5bf Pin paho-mqtt to 1.6.1
Closes #2855
2024-05-16 15:28:05 +02:00
Safihre
989e215acc Update sabctools to 8.2.0 2024-05-16 15:00:26 +02:00
thezoggy
ba88bb15a9 Update unrar 7.01 and 7zip to 24.05 (#2860)
* Update unrar to 7.01

* Upgrade 7zip to 24.05
2024-05-16 09:10:14 +02:00
SABnzbd Automation
0cac0d942c Update translatable texts
[skip ci]
2024-05-15 11:04:15 +00:00
Chris Caron
b24a9ee781 Added tests cases to wrap calls to the Apprise integration (#2856)
* Added tests cases to wrap calls to the Apprise integration

* workaround to default config getting lost from test_misc.py

* 100% test coverage in send_apprise()
2024-05-15 13:03:26 +02:00
SABnzbd Automation
25ae29235f Update translatable texts
[skip ci]
2024-05-13 01:51:57 +00:00
renovate[bot]
a8d4de2d3d Update all dependencies 2024-05-13 01:51:12 +00:00
SABnzbd Automation
ccb3e0522c Update translatable texts
[skip ci]
2024-05-09 20:56:42 +00:00
Safihre
a9f1838b52 Update History Retention wording 2024-05-09 22:55:27 +02:00
SABnzbd Automation
d744c293fb Update translatable texts
[skip ci]
2024-05-09 20:49:42 +00:00
Safihre
94848979ad Add disable_archive for users that want to always skip it
Relates to #2848
2024-05-09 22:47:31 +02:00
SABnzbd Automation
2732326b3d Update translatable texts
[skip ci]
2024-05-06 00:22:01 +00:00
renovate[bot]
ea8328c199 Update all dependencies 2024-05-06 00:21:22 +00:00
115 changed files with 970 additions and 463 deletions

View File

@@ -40,3 +40,4 @@ f06891926661986fff52d6eb4b4cb120c71972d1
9bcbcaefdfecc85aedfd8e2f8aaa1ca7f959404e
433dcab02b29f7bd3827e237434034deecc1b549
9f6a9f991222efccc87b45a701086c95629c67b6
f89114ca7e1b20bf8e645ecd0b52b707ec857aa9

View File

@@ -21,6 +21,7 @@ body:
options:
- linuxserver
- hotio
- binhex
- Other
- type: textarea
attributes:

View File

@@ -4,7 +4,7 @@ contact_links:
url: https://forums.sabnzbd.org/
about: Support questions can be asked on our forums, Reddit or Discord server.
- name: Discord
url: https://discord.gg/KQzDe7fvNU
url: https://discord.sabnzbd.org
about: Support questions can be asked on our forums, Reddit or Discord server.
- name: Reddit - r/sabnzbd
url: https://www.reddit.com/r/sabnzbd

View File

@@ -20,6 +20,7 @@
"jaraco.context",
"jaraco.collections",
"sabctools",
"paho-mqtt",
"werkzeug",
"pyinstaller"
],

View File

@@ -69,7 +69,7 @@ jobs:
# We need the official Python, because the GA ones only support newer macOS versions
# The deployment target is picked up by the Python build tools automatically
# If updated, make sure to also set LSMinimumSystemVersion in SABnzbd.spec
PYTHON_VERSION: "3.12.3"
PYTHON_VERSION: "3.12.5"
MACOSX_DEPLOYMENT_TARGET: "10.9"
# We need to force compile for universal2 support
CFLAGS: -arch x86_64 -arch arm64

View File

@@ -2,7 +2,7 @@ SABnzbd - The automated Usenet download tool
============================================
[![License](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![Join our Discord](https://img.shields.io/discord/976737547558461480?color=7289DA&label=Discord&logo=Discord&logoColor=white)](https://discord.gg/KQzDe7fvNU)
[![Join our Discord](https://img.shields.io/discord/976737547558461480?color=7289DA&label=Discord&logo=Discord&logoColor=white)](https://discord.sabnzbd.org)
SABnzbd is an Open Source Binary Newsreader written in Python.

View File

@@ -1,7 +1,26 @@
Release Notes - SABnzbd 4.3.1
Release Notes - SABnzbd 4.3.3
=========================================================
This is the first bug fix release of SABnzbd 4.3.0.
This is the third bug fix release of SABnzbd 4.3.0.
## Bug fixes and changes since 4.3.2
* Reduced chance of jobs getting stuck at 99%.
* Prevent crash in case of invalid articles.
* Correct handling of empty or `Default` category when adding a job.
* History API-output could contain inconsistent variable types.
* Skip external IPv6 check if only link local addresses are available.
* Shortened timeouts when resolving addresses during checks.
* Windows: Could not repair or extract on ARM platforms.
* Windows: Add file version information to installer.
## Bug fixes and changes since 4.3.1
* Added Special option `disable_archive` for jobs to always be permanently deleted.
* Specific AppRise notifications could fail to send.
* Update of the article decoder core (`rapidyenc`).
* Windows: After some time the interface would no longer load.
* Windows: Custom shortcuts would be removed by the installer.
* Windows/macOS: Updated Unrar to 7.01 and 7zip to 24.05.
## Key changes since 4.2.0

View File

@@ -47,6 +47,7 @@ try:
import feedparser
import configobj
import cherrypy
import cheroot.errors
import portend
import cryptography
import chardet
@@ -64,7 +65,7 @@ import sabnzbd
import sabnzbd.lang
import sabnzbd.interface
from sabnzbd.constants import (
DEF_TIMEOUT,
DEF_NETWORKING_TIMEOUT,
DEF_LOG_ERRFILE,
DEF_MAIN_TMPL,
DEF_STD_WEB_DIR,
@@ -169,7 +170,8 @@ class GUIHandler(logging.Handler):
# This prevents endless looping if the notification service itself throws an error/warning
# We don't check based on message content, because if it includes a timestamp it's not unique
if not any(
stored_warning["origin"] == warning["origin"] and stored_warning["time"] + DEF_TIMEOUT > time.time()
stored_warning["origin"] == warning["origin"]
and stored_warning["time"] + DEF_NETWORKING_TIMEOUT > time.time()
for stored_warning in self.store
):
if record.levelno == logging.WARNING:
@@ -296,14 +298,14 @@ def daemonize():
os.dup2(f.fileno(), sys.stderr.fileno())
def abort_and_show_error(browserhost, cherryport, err=""):
def abort_and_show_error(browserhost, web_port, err=""):
"""Abort program because of CherryPy troubles"""
logging.error(T("Failed to start web-interface") + " : " + str(err))
if not sabnzbd.DAEMON:
if "49" in err:
panic_host(browserhost, cherryport)
panic_host(browserhost, web_port)
else:
panic_port(browserhost, cherryport)
panic_port(browserhost, web_port)
sabnzbd.halt()
exit_sab(2)
@@ -529,19 +531,19 @@ def check_resolve(host):
return True
def get_webhost(cherryhost, cherryport, https_port):
def get_webhost(web_host, web_port, https_port):
"""Determine the webhost address and port,
return (host, port, browserhost)
"""
if cherryhost == "0.0.0.0" and not check_resolve("127.0.0.1"):
cherryhost = ""
elif cherryhost == "::" and not check_resolve("::1"):
cherryhost = ""
if web_host == "0.0.0.0" and not check_resolve("127.0.0.1"):
web_host = ""
elif web_host == "::" and not check_resolve("::1"):
web_host = ""
if cherryhost is None:
cherryhost = sabnzbd.cfg.cherryhost()
if web_host is None:
web_host = sabnzbd.cfg.web_host()
else:
sabnzbd.cfg.cherryhost.set(cherryhost)
sabnzbd.cfg.web_host.set(web_host)
# Get IP address, but discard APIPA/IPV6
# If only APIPA's or IPV6 are found, fall back to localhost
@@ -553,10 +555,10 @@ def get_webhost(cherryhost, cherryport, https_port):
# Hostname does not resolve
try:
# Valid user defined name?
info = socket.getaddrinfo(cherryhost, None)
info = socket.getaddrinfo(web_host, None)
except socket.error:
if not is_localhost(cherryhost):
cherryhost = "0.0.0.0"
if not is_localhost(web_host):
web_host = "0.0.0.0"
try:
info = socket.getaddrinfo(localhost, None)
except socket.error:
@@ -573,75 +575,75 @@ def get_webhost(cherryhost, cherryport, https_port):
hostip = ip
# A blank host will use the local ip address
if cherryhost == "":
if web_host == "":
if ipv6 and ipv4:
# To protect Firefox users, use numeric IP
cherryhost = hostip
web_host = hostip
browserhost = hostip
else:
cherryhost = socket.gethostname()
browserhost = cherryhost
web_host = socket.gethostname()
browserhost = web_host
# 0.0.0.0 will listen on all ipv4 interfaces (no ipv6 addresses)
elif cherryhost == "0.0.0.0":
elif web_host == "0.0.0.0":
# Just take the gamble for this
cherryhost = "0.0.0.0"
web_host = "0.0.0.0"
browserhost = localhost
# :: will listen on all ipv6 interfaces (no ipv4 addresses)
elif cherryhost in ("::", "[::]"):
cherryhost = cherryhost.strip("[").strip("]")
elif web_host in ("::", "[::]"):
web_host = web_host.strip("[").strip("]")
# Assume '::1' == 'localhost'
browserhost = localhost
# IPV6 address
elif "[" in cherryhost or ":" in cherryhost:
browserhost = cherryhost
elif "[" in web_host or ":" in web_host:
browserhost = web_host
# IPV6 numeric address
elif cherryhost.replace(".", "").isdigit():
elif web_host.replace(".", "").isdigit():
# IPV4 numerical
browserhost = cherryhost
browserhost = web_host
elif cherryhost == localhost:
cherryhost = localhost
elif web_host == localhost:
web_host = localhost
browserhost = localhost
else:
# If on APIPA, use numerical IP, to help FireFoxers
if ipv6 and ipv4:
cherryhost = hostip
browserhost = cherryhost
web_host = hostip
browserhost = web_host
# Some systems don't like brackets in numerical ipv6
if sabnzbd.MACOS:
cherryhost = cherryhost.strip("[]")
web_host = web_host.strip("[]")
else:
try:
socket.getaddrinfo(cherryhost, None)
socket.getaddrinfo(web_host, None)
except socket.error:
cherryhost = cherryhost.strip("[]")
web_host = web_host.strip("[]")
if ipv6 and ipv4 and cherryhost == "" and sabnzbd.WIN32:
if ipv6 and ipv4 and web_host == "" and sabnzbd.WIN32:
helpful_warning(T("Please be aware the 0.0.0.0 hostname will need an IPv6 address for external access"))
if cherryhost == "localhost" and not sabnzbd.WIN32 and not sabnzbd.MACOS:
if web_host == "localhost" and not sabnzbd.WIN32 and not sabnzbd.MACOS:
# On the Ubuntu family, localhost leads to problems for CherryPy
ips = ip_extract()
if "127.0.0.1" in ips and "::1" in ips:
cherryhost = "127.0.0.1"
web_host = "127.0.0.1"
if ips[0] != "127.0.0.1":
browserhost = "127.0.0.1"
# This is to please Chrome on macOS
if cherryhost == "localhost" and sabnzbd.MACOS:
cherryhost = "127.0.0.1"
if web_host == "localhost" and sabnzbd.MACOS:
web_host = "127.0.0.1"
browserhost = "localhost"
if cherryport is None:
cherryport = sabnzbd.cfg.cherryport.get_int()
if web_port is None:
web_port = sabnzbd.cfg.web_port.get_int()
else:
sabnzbd.cfg.cherryport.set(str(cherryport))
sabnzbd.cfg.web_port.set(str(web_port))
if https_port is None:
https_port = sabnzbd.cfg.https_port.get_int()
@@ -650,12 +652,12 @@ def get_webhost(cherryhost, cherryport, https_port):
# if the https port was specified, assume they want HTTPS enabling also
sabnzbd.cfg.enable_https.set(True)
if cherryport == https_port and sabnzbd.cfg.enable_https():
if web_port == https_port and sabnzbd.cfg.enable_https():
sabnzbd.cfg.enable_https.set(False)
# Should have a translated message, but that's not available yet
logging.error(T("HTTP and HTTPS ports cannot be the same"))
return cherryhost, cherryport, browserhost, https_port
return web_host, web_port, browserhost, https_port
def attach_server(host, port, cert=None, key=None, chain=None):
@@ -840,8 +842,8 @@ def main():
fork = False
pause = False
inifile = None
cherryhost = None
cherryport = None
web_host = None
web_port = None
https_port = None
cherrypylogging = None
clean_up = False
@@ -879,14 +881,11 @@ def main():
elif opt in ("-t", "--templates"):
web_dir = arg
elif opt in ("-s", "--server"):
(cherryhost, cherryport) = split_host(arg)
(web_host, web_port) = split_host(arg)
elif opt in ("-n", "--nobrowser"):
autobrowser = False
elif opt in ("-b", "--browser"):
try:
autobrowser = bool(int(arg))
except ValueError:
autobrowser = True
autobrowser = sabnzbd.misc.bool_conv(arg)
elif opt == "--autorestarted":
autorestarted = True
elif opt in ("-c", "--clean"):
@@ -1005,24 +1004,24 @@ def main():
sabnzbd.cfg.ipv6_hosting.set(ipv6_hosting)
# Determine web host address
cherryhost, cherryport, browserhost, https_port = get_webhost(cherryhost, cherryport, https_port)
web_host, web_port, browserhost, https_port = get_webhost(web_host, web_port, https_port)
enable_https = sabnzbd.cfg.enable_https()
# 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(cherryhost, https_port, timeout=0.05)
portend.free(web_host, https_port, timeout=0.05)
except IOError:
abort_and_show_error(browserhost, cherryport)
abort_and_show_error(browserhost, web_port)
except:
abort_and_show_error(browserhost, cherryport, "49")
abort_and_show_error(browserhost, web_port, "49")
try:
portend.free(cherryhost, cherryport, timeout=0.05)
portend.free(web_host, web_port, timeout=0.05)
except IOError:
abort_and_show_error(browserhost, cherryport)
abort_and_show_error(browserhost, web_port)
except:
abort_and_show_error(browserhost, cherryport, "49")
abort_and_show_error(browserhost, web_port, "49")
# Windows instance is reachable through registry
url = None
@@ -1033,7 +1032,7 @@ def main():
# SSL
if enable_https:
port = https_port or cherryport
port = https_port or web_port
try:
portend.free(browserhost, port, timeout=0.05)
except IOError as error:
@@ -1045,7 +1044,7 @@ def main():
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, cherryport)
abort_and_show_error(browserhost, web_port)
# Find free port to bind
newport = find_free_port(browserhost, port)
if newport > 0:
@@ -1055,34 +1054,34 @@ def main():
sabnzbd.cfg.https_port.set(newport)
else:
# In case HTTPS == HTTP port
cherryport = newport
sabnzbd.cfg.cherryport.set(newport)
web_port = newport
sabnzbd.cfg.web_port.set(newport)
except:
# Something else wrong, probably badly specified host
abort_and_show_error(browserhost, cherryport, "49")
abort_and_show_error(browserhost, web_port, "49")
# 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, cherryport, timeout=0.05)
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, cherryport, sabnzbd.cfg.url_base())
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, cherryport)
abort_and_show_error(browserhost, web_port)
# Find free port to bind
port = find_free_port(browserhost, cherryport)
port = find_free_port(browserhost, web_port)
if port > 0:
sabnzbd.cfg.cherryport.set(port)
cherryport = port
sabnzbd.cfg.web_port.set(port)
web_port = port
except:
# Something else wrong, probably badly specified host
abort_and_show_error(browserhost, cherryport, "49")
abort_and_show_error(browserhost, web_port, "49")
# We found a port, now we never check again
sabnzbd.cfg.fixed_ports.set(True)
@@ -1094,8 +1093,7 @@ def main():
sys.exit(1)
if clean_up:
xlist = globber_full(logdir)
for x in xlist:
for x in globber_full(logdir):
if RSS_FILE_NAME not in x:
try:
os.remove(x)
@@ -1277,29 +1275,29 @@ def main():
# Starting of the webserver
# Determine if this system has multiple definitions for 'localhost'
hosts = all_localhosts()
multilocal = len(hosts) > 1 and cherryhost in ("localhost", "0.0.0.0")
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 cherryhost == "0.0.0.0" and hosts[1] == "127.0.0.1":
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 cherryhost == "localhost":
cherryhost = hosts[0]
if web_host == "localhost":
web_host = hosts[0]
if enable_https:
if https_port:
# Extra HTTP port for primary localhost
attach_server(cherryhost, cherryport)
attach_server(web_host, web_port)
if multilocal:
# Extra HTTP port for secondary localhost
attach_server(hosts[1], cherryport)
attach_server(hosts[1], web_port)
# Extra HTTPS port for secondary localhost
attach_server(hosts[1], https_port, https_cert, https_key, https_chain)
cherryport = https_port
web_port = https_port
elif multilocal:
# Extra HTTPS port for secondary localhost
attach_server(hosts[1], cherryport, https_cert, https_key, https_chain)
attach_server(hosts[1], web_port, https_cert, https_key, https_chain)
cherrypy.config.update(
{
@@ -1311,7 +1309,7 @@ def main():
)
elif multilocal:
# Extra HTTP port for secondary localhost
attach_server(hosts[1], cherryport)
attach_server(hosts[1], web_port)
if no_login:
sabnzbd.cfg.username.set("")
@@ -1334,8 +1332,8 @@ def main():
cherrypy.config.update(
{
"server.environment": "production",
"server.socket_host": cherryhost,
"server.socket_port": cherryport,
"server.socket_host": web_host,
"server.socket_port": web_port,
"server.shutdown_timeout": 0,
"engine.autoreload.on": False,
"tools.encode.on": True,
@@ -1347,6 +1345,13 @@ def main():
}
)
# 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
@@ -1396,7 +1401,7 @@ def main():
# Set authentication for CherryPy
sabnzbd.interface.set_auth(cherrypy.config)
logging.info("Starting web-interface on %s:%s", cherryhost, cherryport)
logging.info("Starting web-interface on %s:%s", web_host, web_port)
sabnzbd.cfg.log_level.callback(guard_loglevel)
@@ -1406,7 +1411,7 @@ def main():
# 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, cherryport)
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:
@@ -1416,16 +1421,16 @@ def main():
# Set URL for browser
if enable_https:
sabnzbd.BROWSER_URL = "https://%s:%s%s" % (browserhost, cherryport, sabnzbd.cfg.url_base())
sabnzbd.BROWSER_URL = "https://%s:%s%s" % (browserhost, web_port, sabnzbd.cfg.url_base())
else:
sabnzbd.BROWSER_URL = "http://%s:%s%s" % (browserhost, cherryport, sabnzbd.cfg.url_base())
sabnzbd.BROWSER_URL = "http://%s:%s%s" % (browserhost, web_port, sabnzbd.cfg.url_base())
if sabnzbd.WIN32:
# Write URL for uploads and version check directly to registry
set_connection_info(f"{sabnzbd.BROWSER_URL}/api?apikey={sabnzbd.cfg.api_key()}")
if pid_path or pid_file:
sabnzbd.pid_file(pid_path, pid_file, cherryport)
sabnzbd.pid_file(pid_path, pid_file, web_port)
# Stop here in case of fatal errors
if sabnzbd.NO_DOWNLOADING:
@@ -1453,11 +1458,11 @@ def main():
autorestarted = False
# Start SSDP and Bonjour if SABnzbd isn't listening on localhost only
if sabnzbd.cfg.enable_broadcast() and not is_localhost(cherryhost):
if sabnzbd.cfg.enable_broadcast() and not is_localhost(web_host):
# Try to find a LAN IP address for SSDP/Bonjour
if is_lan_addr(cherryhost):
if is_lan_addr(web_host):
# A specific listening address was configured, use that
external_host = cherryhost
external_host = web_host
else:
# Fall back to the IPv4 address of the LAN interface
external_host = local_ipv4()
@@ -1471,13 +1476,13 @@ def main():
(not sabnzbd.cfg.local_ranges()) or any(ip_in_subnet(external_host, r) for r in sabnzbd.cfg.local_ranges())
):
# Start Bonjour and SSDP
sabnzbd.zconfig.set_bonjour(external_host, cherryport)
sabnzbd.zconfig.set_bonjour(external_host, web_port)
# Set URL for browser for external hosts
ssdp_url = "%s://%s:%s%s" % (
("https" if enable_https else "http"),
external_host,
cherryport,
web_port,
sabnzbd.cfg.url_base(),
)
ssdp.start_ssdp(

View File

@@ -1,6 +1,5 @@
# -*- mode: python -*-
import os
import re
import sys
from PyInstaller.building.api import EXE, COLLECT, PYZ
@@ -8,13 +7,13 @@ from PyInstaller.building.build_main import Analysis
from PyInstaller.building.osx import BUNDLE
from PyInstaller.utils.hooks import collect_data_files, collect_submodules
from builder.constants import EXTRA_FILES, EXTRA_FOLDERS, RELEASE_VERSION
from builder.constants import EXTRA_FILES, EXTRA_FOLDERS, RELEASE_VERSION, RELEASE_VERSION_TUPLE
# Add extra files in the PyInstaller-spec
extra_pyinstaller_files = []
# Add hidden imports
extra_hiddenimports = ["Cheetah.DummyTransaction", "cheroot.ssl.builtin", "certifi"]
extra_hiddenimports = ["Cheetah.DummyTransaction", "cheroot.ssl.builtin", "certifi", "pkg_resources.extern"]
extra_hiddenimports.extend(collect_submodules("apprise"))
extra_hiddenimports.extend(collect_submodules("babelfish.converters"))
extra_hiddenimports.extend(collect_submodules("guessit.data"))
@@ -45,16 +44,12 @@ else:
EXTRA_FOLDERS += ["win/multipar/", "win/par2/", "win/unrar/", "win/7zip/"]
EXTRA_FILES += ["portable.cmd"]
# Parse the version info
version_regexed = re.search(r"(\d+)\.(\d+)\.(\d+)([a-zA-Z]*)(\d*)", RELEASE_VERSION)
version_tuple = (int(version_regexed.group(1)), int(version_regexed.group(2)), int(version_regexed.group(3)), 0)
# Detailed instructions are in the PyInstaller documentation
# We don't include the alpha/beta/rc in the counters
version_info = VSVersionInfo(
ffi=FixedFileInfo(
filevers=version_tuple,
prodvers=version_tuple,
filevers=RELEASE_VERSION_TUPLE,
prodvers=RELEASE_VERSION_TUPLE,
mask=0x3F,
flags=0x0,
OS=0x40004,

View File

@@ -16,6 +16,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import os
import re
# Constants
VERSION_FILE = "sabnzbd/version.py"
@@ -33,6 +34,10 @@ RELEASE_VERSION = __version__
# Pre-releases are longer than 6 characters (e.g. 3.1.0Beta1 vs 3.1.0, but also 3.0.11)
PRERELEASE = len(RELEASE_VERSION) > 5
# Parse the version info for Windows file properties information
version_regexed = re.search(r"(\d+)\.(\d+)\.(\d+)([a-zA-Z]*)(\d*)", RELEASE_VERSION)
RELEASE_VERSION_TUPLE = (int(version_regexed.group(1)), int(version_regexed.group(2)), int(version_regexed.group(3)), 0)
# Define release name
RELEASE_NAME = "SABnzbd-%s" % RELEASE_VERSION
RELEASE_TITLE = "SABnzbd %s" % RELEASE_VERSION

View File

@@ -32,6 +32,7 @@ from typing import List
from constants import (
RELEASE_VERSION,
RELEASE_VERSION_TUPLE,
VERSION_FILE,
RELEASE_README,
RELEASE_NAME,
@@ -258,8 +259,8 @@ if __name__ == "__main__":
[
"makensis.exe",
"/V3",
"/DSAB_PRODUCT=%s" % RELEASE_NAME,
"/DSAB_VERSION=%s" % RELEASE_VERSION,
"/DSAB_VERSIONKEY=%s" % ".".join(map(str, RELEASE_VERSION_TUPLE)),
"/DSAB_FILE=%s" % RELEASE_INSTALLER,
"NSIS_Installer.nsi.tmp",
]

View File

@@ -1,26 +1,26 @@
# Basic build requirements
# Note that not all sub-dependencies are listed, but only ones we know could cause trouble
pyinstaller==5.13.2
packaging==24.0
pyinstaller-hooks-contrib==2024.5
packaging==24.1
pyinstaller-hooks-contrib==2024.8
altgraph==0.17.4
wrapt==1.16.0
setuptools==69.5.1
setuptools==72.1.0
# Required on 32bit Windows, exclude it based on Python-version
importlib_metadata==7.1.0; python_version < '3.10'
importlib_metadata==8.2.0; python_version < '3.10'
importlib_resources==6.4.0; python_version < '3.10'
zipp==3.18.1; python_version < '3.10'
zipp==3.20.0; python_version < '3.10'
# orjson does not support 32bit Windows, also exclude based on Python-version
orjson==3.10.1; python_version > '3.8'
orjson==3.10.7; python_version > '3.8'
# For the Windows build
pefile==2023.2.7; sys_platform == 'win32'
pywin32-ctypes==0.2.2; sys_platform == 'win32'
# For the macOS build
dmgbuild==1.6.1; sys_platform == 'darwin'
dmgbuild==1.6.2; sys_platform == 'darwin'
mac-alias==2.2.2; sys_platform == 'darwin'
macholib==1.16.3; sys_platform == 'darwin'
ds-store==1.3.1; sys_platform == 'darwin'

View File

@@ -40,8 +40,11 @@ Unicode true
; Remove the whole dir
; Users should not be putting stuff here!
RMDir /r "${idir}"
!macroend
; Remove any shortuts, starting with current user ones (from old installs)
!define RemovePrevShortcuts "!insertmacro RemovePrevShortcuts"
!macro RemovePrevShortcuts
; Remove shortcuts, starting with current user ones (from old installs)
SetShellVarContext current
!insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
Delete "$SMPROGRAMS\$MUI_TEMP\SABnzbd.lnk"
@@ -65,7 +68,18 @@ Unicode true
;------------------------------------------------------------------
; Define names of the product
Name "${SAB_PRODUCT}"
Name "SABnzbd ${SAB_VERSION}"
VIProductVersion "${SAB_VERSIONKEY}"
VIFileVersion "${SAB_VERSIONKEY}"
VIAddVersionKey "Comments" "SABnzbd ${SAB_VERSION}"
VIAddVersionKey "CompanyName" "The SABnzbd-Team"
VIAddVersionKey "FileDescription" "SABnzbd ${SAB_VERSION}"
VIAddVersionKey "FileVersion" "${SAB_VERSION}"
VIAddVersionKey "LegalCopyright" "The SABnzbd-Team"
VIAddVersionKey "ProductName" "SABnzbd ${SAB_VERSION}"
VIAddVersionKey "ProductVersion" "${SAB_VERSION}"
OutFile "${SAB_FILE}"
InstallDir "$PROGRAMFILES\SABnzbd"
@@ -314,13 +328,13 @@ Function .onInit
endCheckStartup:
SetShellVarContext current
IfFileExists "$DESKTOP\SABnzbd.lnk" endCheckDesktopCurrent 0
SectionSetFlags ${desktop} 0 ; SAB is installed but desktop-icon not, so uncheck it
endCheckDesktopCurrent:
SetShellVarContext all
IfFileExists "$DESKTOP\SABnzbd.lnk" endCheckDesktop 0
SectionSetFlags ${desktop} 0 ; SAB is installed but desktop-icon not, so uncheck it
; If not present for current user, first check all user folder
SetShellVarContext all
IfFileExists "$DESKTOP\SABnzbd.lnk" endCheckDesktop 0
SectionSetFlags ${desktop} 0 ; SAB is installed but desktop-icon not, so uncheck it
endCheckDesktop:
SetShellVarContext all
Push $1
ReadRegStr $1 HKCR ".nzb" "" ; read current file association
@@ -374,6 +388,7 @@ Section "un.$(MsgDelProgram)" Uninstall
DeleteRegKey HKEY_CURRENT_USER "Software\SABnzbd"
${RemovePrev} "$INSTDIR"
${RemovePrevShortcuts}
; Remove firewall entries
liteFirewallW::RemoveRule "$INSTDIR\SABnzbd.exe" "SABnzbd"

View File

@@ -26,7 +26,7 @@
</div>
<div class="field-pair">
<label class="config" for="port">$T('opt-port')</label>
<input type="number" name="port" id="port" value="$port" size="8" data-original="$port" />
<input type="number" name="port" id="port" value="$port" size="8" data-original="$port" min="0" max="65535" />
<span class="desc">$T('explain-port')</span>
</div>
<div class="field-pair">
@@ -69,7 +69,7 @@
</div>
<div class="field-pair advanced-settings">
<label class="config" for="https_port">$T('opt-https_port')</label>
<input type="number" name="https_port" id="https_port" value="$https_port" size="8" data-original="$https_port" />
<input type="number" name="https_port" id="https_port" value="$https_port" size="8" data-original="$https_port" min="0" max="65535" />
<span class="desc">$T('explain-https_port')</span>
</div>
<div class="field-pair advanced-settings">

View File

@@ -10,13 +10,13 @@
<label class="config wide" 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 int($getVar($section_label + '_prio_' + $type)) > 0 then 'checked="checked"' else ""#--> />
<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#-->
<!--#def show_cat_box($section_label)#-->
<div class="col2-cats" <!--#if int($getVar($section_label + '_enable')) > 0 then '' else 'style="display:none"'#-->>
<div class="col2-cats" <!--#if $getVar($section_label + '_enable') then '' else 'style="display:none"'#-->>
<hr>
<b>$T('affectedCat')</b><br/>
<select name="${section_label}_cats" multiple="multiple" class="multiple_cats" size="$len($categories)">
@@ -58,12 +58,12 @@
</div>
<div class="field-pair">
<label class="config" for="email_full">$T('opt-email_full')</label>
<input type="checkbox" name="email_full" id="email_full" value="1" <!--#if int($email_full) > 0 then 'checked="checked"' else ""#--> />
<input type="checkbox" name="email_full" id="email_full" value="1" <!--#if $email_full then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-email_full')</span>
</div>
<div class="field-pair">
<label class="config" for="email_rss">$T('opt-email_rss')</label>
<input type="checkbox" name="email_rss" id="email_rss" value="1" <!--#if int($email_rss) > 0 then 'checked="checked"' else ""#--> />
<input type="checkbox" name="email_rss" id="email_rss" value="1" <!--#if $email_rss then 'checked="checked"' else ""#--> />
<span class="desc">$T('explain-email_rss')</span>
</div>
<div class="field-pair">
@@ -107,12 +107,12 @@
<h3>$T('section-NC')</h3>
<table>
<tr>
<td><input type="checkbox" name="ncenter_enable" id="ncenter_enable" value="1" <!--#if int($ncenter_enable) > 0 then 'checked="checked"' else ""#--> /></td>
<td><input type="checkbox" name="ncenter_enable" id="ncenter_enable" value="1" <!--#if $ncenter_enable then 'checked="checked"' else ""#--> /></td>
<td><label for="ncenter_enable"> $T('opt-ncenter_enable')</label></td>
</tr>
</table>
</div>
<div class="col1" <!--#if int($ncenter_enable) > 0 then '' else 'style="display:none"'#-->>
<div class="col1" <!--#if $ncenter_enable then '' else 'style="display:none"'#-->>
<fieldset>
$show_notify_checkboxes('ncenter')
<div class="field-pair no-field-pair-bg">
@@ -132,13 +132,13 @@
<h3>$T('section-AC')</h3>
<table>
<tr>
<td><input type="checkbox" name="acenter_enable" id="acenter_enable" value="1" <!--#if int($acenter_enable) > 0 then 'checked="checked"' else ""#--> /></td>
<td><input type="checkbox" name="acenter_enable" id="acenter_enable" value="1" <!--#if $acenter_enable then 'checked="checked"' else ""#--> /></td>
<td><label for="acenter_enable"> $T('opt-acenter_enable')</label></td>
</tr>
</table>
$show_cat_box('acenter')
</div>
<div class="col1" <!--#if int($acenter_enable) > 0 then '' else 'style="display:none"'#-->>
<div class="col1" <!--#if $acenter_enable then '' else 'style="display:none"'#-->>
<fieldset>
$show_notify_checkboxes('acenter')
<div class="field-pair no-field-pair-bg">
@@ -158,13 +158,13 @@
<h3>$T('section-OSD') <a href="$help_uri#toc4" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
<table>
<tr>
<td><input type="checkbox" name="ntfosd_enable" id="ntfosd_enable" value="1" <!--#if int($ntfosd_enable) > 0 then 'checked="checked"' else ""#--> /></td>
<td><input type="checkbox" name="ntfosd_enable" id="ntfosd_enable" value="1" <!--#if $ntfosd_enable then 'checked="checked"' else ""#--> /></td>
<td><label for="ntfosd_enable"> $T('opt-ntfosd_enable')</label></td>
</tr>
</table>
$show_cat_box('ntfosd')
</div>
<div class="col1" <!--#if int($ntfosd_enable) > 0 then '' else 'style="display:none"'#-->>
<div class="col1" <!--#if $ntfosd_enable then '' else 'style="display:none"'#-->>
<fieldset>
$show_notify_checkboxes('ntfosd')
<div class="field-pair no-field-pair-bg">
@@ -183,7 +183,7 @@
<h3>Apprise <a href="$help_uri#apprise" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
<table>
<tr>
<td><input type="checkbox" name="apprise_enable" id="apprise_enable" value="1" <!--#if int($apprise_enable) > 0 then 'checked="checked"' else ""#--> /></td>
<td><input type="checkbox" name="apprise_enable" id="apprise_enable" value="1" <!--#if $apprise_enable then 'checked="checked"' else ""#--> /></td>
<td><label for="apprise_enable"> $T('opt-apprise_enable')</label></td>
</tr>
</table>
@@ -192,7 +192,7 @@
$show_cat_box('apprise')
</div>
<div class="col1" <!--#if int($apprise_enable) > 0 then '' else 'style="display:none"'#-->>
<div class="col1" <!--#if $apprise_enable then '' else 'style="display:none"'#-->>
<fieldset>
<div class="field-pair">
<label class="config" for="apprise_urls">$T('opt-apprise_urls')</label>
@@ -208,7 +208,7 @@
<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 int($getVar($section_label + '_target_' + $type + '_enable')) > 0 then 'checked="checked"' else ""#--> />
<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="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#-->
@@ -228,14 +228,14 @@
<h3>$T('section-NScript') <a href="$help_uri#nscript" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></h3>
<table>
<tr>
<td><input type="checkbox" name="nscript_enable" id="nscript_enable" value="1" <!--#if int($nscript_enable) > 0 then 'checked="checked"' else ""#--> /></td>
<td><input type="checkbox" name="nscript_enable" id="nscript_enable" value="1" <!--#if $nscript_enable then 'checked="checked"' else ""#--> /></td>
<td><label for="nscript_enable"> $T('opt-nscript_enable')</label></td>
</tr>
</table>
<em>$T('explain-nscript_enable')</em><br><a href="$help_uri#nscript" target="_blank">$T('readwiki')</a>
$show_cat_box('nscript')
</div>
<div class="col1" <!--#if int($nscript_enable) > 0 then '' else 'style="display:none"'#-->>
<div class="col1" <!--#if $nscript_enable then '' else 'style="display:none"'#-->>
<fieldset>
<div class="field-pair">
<label class="config" for="nscript_script">$T('opt-nscript_script')</label>
@@ -267,14 +267,14 @@
<h3>$T('section-Prowl')</h3>
<table>
<tr>
<td><input type="checkbox" name="prowl_enable" id="prowl_enable" value="1" <!--#if int($prowl_enable) > 0 then 'checked="checked"' else ""#--> /></td>
<td><input type="checkbox" name="prowl_enable" id="prowl_enable" value="1" <!--#if $prowl_enable then 'checked="checked"' else ""#--> /></td>
<td><label for="prowl_enable"> $T('opt-prowl_enable')</label></td>
</tr>
</table>
<em>$T('explain-prowl_enable')</em>
$show_cat_box('prowl')
</div>
<div class="col1" <!--#if int($prowl_enable) > 0 then '' else 'style="display:none"'#-->>
<div class="col1" <!--#if $prowl_enable then '' else 'style="display:none"'#-->>
<fieldset>
<div class="field-pair">
<label class="config" for="prowl_apikey">$T('opt-prowl_apikey')</label>
@@ -313,14 +313,14 @@
<h3>$T('section-Pushover')</h3>
<table>
<tr>
<td><input type="checkbox" name="pushover_enable" id="pushover_enable" value="1" <!--#if int($pushover_enable) > 0 then 'checked="checked"' else ""#--> /></td>
<td><input type="checkbox" name="pushover_enable" id="pushover_enable" value="1" <!--#if $pushover_enable then 'checked="checked"' else ""#--> /></td>
<td><label for="pushover_enable"> $T('opt-pushover_enable')</label></td>
</tr>
</table>
<em>$T('explain-pushover_enable')</em>
$show_cat_box('pushover')
</div>
<div class="col1" <!--#if int($pushover_enable) > 0 then '' else 'style="display:none"'#-->>
<div class="col1" <!--#if $pushover_enable then '' else 'style="display:none"'#-->>
<fieldset>
<div class="field-pair">
<label class="config" for="pushover_token">$T('opt-pushover_token')</label>
@@ -378,14 +378,14 @@
<h3>$T('section-Pushbullet')</h3>
<table>
<tr>
<td><input type="checkbox" name="pushbullet_enable" id="pushbullet_enable" value="1" <!--#if int($pushbullet_enable) > 0 then 'checked="checked"' else ""#--> /></td>
<td><input type="checkbox" name="pushbullet_enable" id="pushbullet_enable" value="1" <!--#if $pushbullet_enable then 'checked="checked"' else ""#--> /></td>
<td><label for="pushbullet_enable"> $T('opt-pushbullet_enable')</label></td>
</tr>
</table>
<em>$T('explain-pushbullet_enable')</em>
$show_cat_box('pushbullet')
</div>
<div class="col1" <!--#if int($pushbullet_enable) > 0 then '' else 'style="display:none"'#-->>
<div class="col1" <!--#if $pushbullet_enable then '' else 'style="display:none"'#-->>
<fieldset>
<div class="field-pair">
<label class="config" for="pushbullet_apikey">$T('opt-pushbullet_apikey')</label>

View File

@@ -59,7 +59,7 @@
</div>
<div class="field-pair advanced-settings">
<label class="config" for="port">$T('srv-port')</label>
<input type="number" name="port" id="port" size="8" value="563" min="0" />
<input type="number" name="port" id="port" size="8" value="563" min="0" max="65535" />
</div>
<div class="field-pair">
<label class="config" for="ssl">$T('srv-ssl')</label>
@@ -185,7 +185,7 @@
</div>
<div class="field-pair advanced-settings">
<label class="config" for="port$cur">$T('srv-port')</label>
<input type="number" name="port" id="port$cur" value="$server['port']" size="8" min="0" required />
<input type="number" name="port" id="port$cur" value="$server['port']" size="8" min="0" max="65535" required />
</div>
<div class="field-pair">
<label class="config" for="ssl$cur">$T('srv-ssl')</label>

View File

@@ -69,7 +69,7 @@
</div>
<div class="field-pair">
<label class="config" for="propagation_delay">$T('opt-propagation_delay')</label>
<input type="number" name="propagation_delay" id="propagation_delay" value="$propagation_delay" /> <i>$T('minutes')</i>
<input type="number" name="propagation_delay" id="propagation_delay" value="$propagation_delay" min="0" /> <i>$T('minutes')</i>
<span class="desc">$T('explain-propagation_delay')</span>
</div>
<div class="field-pair advanced-settings">

View File

@@ -36,8 +36,8 @@
<div class="alert alert-danger" role="alert">$error</div>
<!--#end if#-->
<input type="text" class="form-control" name="username" placeholder="$T('srv-username')" required autofocus>
<input type="password" class="form-control" name="password" placeholder="$T('srv-password')" required>
<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>
<button class="btn btn-default"><span class="glyphicon glyphicon-circle-arrow-right"></span> $T('login') </button>
@@ -62,4 +62,4 @@
} catch(err) { }
</script>
</body>
</html>
</html>

View File

@@ -208,7 +208,7 @@ ul.tabs a,
#subscriptions,
.RSS form[action="add_rss_feed"] tr:nth-child(even),
.Config .table {
border: 1px solid #555555 !important;
border: 1px solid #555555;
}
.Categories form:first-of-type tr:last-of-type,

View File

@@ -19,6 +19,7 @@ body {
float: left;
overflow: visible;
border: 1px solid #dfdede;
border-bottom: none !important;
background-color: #FFF;
width: 100%
}
@@ -1222,7 +1223,6 @@ input[type="checkbox"] {
}
.value-and-select select {
min-width: 30px;
margin-top: 1px;
}
.dotOne, .dotTwo, .dotThree {

View File

@@ -135,7 +135,7 @@
<div class="col-sm-6 col-dot-overflow" data-bind="visible: hasPerformanceInfo">
<span data-bind="text: statusInfo.pystone"></span>
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest') (~10 $T('seconds'))"><span class="glyphicon glyphicon-repeat"></span></a>
<small title="$cpumodel $cpusimd" data-tooltip="true">$cpumodel $cpusimd</small>
<small title="$cpumodel $cpusimd $docker" data-tooltip="true">$cpumodel $cpusimd $docker</small>
</div>
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
</div>
@@ -528,7 +528,7 @@
<div class="form-group">
<label class="col-sm-4 control-label">$T('category')</label>
<div class="col-sm-6">
<select name="Category" class="form-control" data-bind="options: queue.categoriesList, optionsValue: 'catValue', optionsText: 'catText'"></select>
<select name="Category" class="form-control" data-bind="options: queue.categoriesList, optionsValue: 'catValue', optionsText: 'catText', optionsCaption: ''"></select>
<span class="glyphicon glyphicon-tag"></span>
</div>
</div>
@@ -537,7 +537,7 @@
<div class="col-sm-6">
<!-- This list is different from the one during download! -->
<select name="Priority" class="form-control">
<option value="-100">$T('default')</option>
<option value=""></option>
<option value="2">$T('pr-force')</option>
<option value="1">$T('pr-high')</option>
<option value="0">$T('pr-normal')</option>
@@ -550,14 +550,14 @@
<div class="form-group">
<label class="col-sm-4 control-label">$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: '$T('default')'"></select>
<select name="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>
<div class="col-sm-6">
<select name="Post-processing" class="form-control" data-bind="options: queue.scriptsList, optionsCaption: '$T('default')', optionsValue: 'scriptValue', optionsText: 'scriptText', enable: (queue.scriptsList().length > 1)"></select>
<select name="Post-processing" 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>

View File

@@ -704,6 +704,7 @@ function ViewModel() {
data.append("apikey", apiKey);
// Add this one
debugger
$.ajax({
url: "./api",
type: "POST",

View File

@@ -57,13 +57,13 @@
<div class="form-group">
<label for="port" class="col-sm-4 control-label">$T('srv-port')</label>
<div class="col-sm-8">
<input type="number" class="form-control" name="port" id="port" value="<!--#if $port then $port else '563' #-->" />
<input type="number" class="form-control" name="port" id="port" value="<!--#if $port then $port else '563' #-->" min="0" max="65535" />
</div>
</div>
<div class="form-group">
<label for="connections" class="col-sm-4 control-label">$T('srv-connections')</label>
<div class="col-sm-8">
<input type="number" class="form-control" name="connections" id="connections" value="<!--#if $connections then $connections else '8'#-->" data-toggle="tooltip" data-placement="right" title="$T('wizard-server-con-explain') $T('wizard-server-con-eg')" />
<input type="number" class="form-control" name="connections" id="connections" value="<!--#if $connections then $connections else '8'#-->" min="1" max="500" data-toggle="tooltip" data-placement="right" title="$T('wizard-server-con-explain') $T('wizard-server-con-eg')" />
</div>
</div>
<div class="form-group">

View File

@@ -30,6 +30,8 @@
<url type="faq">https://sabnzbd.org/wiki/faq</url>
<url type="contact">https://sabnzbd.org/live-chat.html</url>
<releases>
<release version="4.3.3" date="2024-08-20" type="stable"/>
<release version="4.3.2" date="2024-05-30" type="stable"/>
<release version="4.3.1" date="2024-05-03" type="stable"/>
<release version="4.3.0" date="2024-05-01" type="stable"/>
<release version="4.2.2" date="2024-02-01" type="stable"/>

View File

@@ -22,6 +22,11 @@ ExecStart=/opt/sabnzbd/SABnzbd.py --disable-file-log --logging 1 --browser 0
User=%I
Type=simple
Restart=on-failure
ProtectSystem=full
DeviceAllow=/dev/null rw
DeviceAllow=/dev/urandom r
DevicePolicy=strict
NoNewPrivileges=yes
[Install]
WantedBy=multi-user.target

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,7 +4,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: team@sabnzbd.org\n"
"Language-Team: SABnzbd <team@sabnzbd.org>\n"
@@ -1082,6 +1082,11 @@ msgstr ""
msgid "Failed to send Prowl message"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2697,7 +2702,7 @@ msgid "Move jobs to the archive if the history exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid "Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2705,7 +2710,7 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid "Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Czech (https://app.transifex.com/sabnzbd/teams/111101/cs/)\n"
@@ -1154,6 +1154,11 @@ msgstr "Nepodařilo se odeslat macOS oznámení"
msgid "Failed to send Prowl message"
msgstr "Nepodařilo se odeslat Prowl zprávu"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2809,7 +2814,8 @@ msgid ""
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2817,7 +2823,8 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Danish (https://app.transifex.com/sabnzbd/teams/111101/da/)\n"
@@ -1161,6 +1161,11 @@ msgstr ""
msgid "Failed to send Prowl message"
msgstr "Kunne ikke sende Prowl besked"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2859,7 +2864,8 @@ msgid ""
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2867,7 +2873,8 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

@@ -13,12 +13,13 @@
# kameb, 2023
# HandyDandy04, 2024
# Safihre <safihre@sabnzbd.org>, 2024
# Gjelbrim Haskaj, 2024
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0RC1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2024\n"
"Last-Translator: Gjelbrim Haskaj, 2024\n"
"Language-Team: German (https://app.transifex.com/sabnzbd/teams/111101/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -206,6 +207,9 @@ msgid ""
"server (port 80), possibly an indexer, not a usenet server. You have to fill"
" a usenet server."
msgstr ""
"Verbindung zu %s auf Port %s konnte nicht hergestellt werden. Es scheint, "
"als sei %s ein Webserver (Port 80), vielleicht ein Indexer, aber kein "
"Usenet-Server. Trage einen Usenet-Server ein."
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Server address \"%s:%s\" is not valid."
@@ -1152,7 +1156,7 @@ msgstr "Wiki"
#: sabnzbd/newswrapper.py
msgid "Failed to connect: %s %s@%s:%s (%s)"
msgstr ""
msgstr "Verbindung fehlgeschlagen: %s %s@%s:%s(%s)"
#. Notification
#: sabnzbd/notifier.py
@@ -1224,6 +1228,11 @@ msgstr "Senden von macOS Benachrichtigung fehlgeschlagen"
msgid "Failed to send Prowl message"
msgstr "Prowl-Nachricht konnte nicht versendet werden"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2964,7 +2973,8 @@ msgid ""
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2972,7 +2982,8 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

@@ -8,7 +8,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Spanish (https://app.transifex.com/sabnzbd/teams/111101/es/)\n"
@@ -1201,6 +1201,11 @@ msgstr "Fallo al enviar la notificación macOS"
msgid "Failed to send Prowl message"
msgstr "No se pudo enviar el mensaje de Prowl"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2926,7 +2931,8 @@ msgid ""
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2934,7 +2940,8 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Finnish (https://app.transifex.com/sabnzbd/teams/111101/fi/)\n"
@@ -1153,6 +1153,11 @@ msgstr ""
msgid "Failed to send Prowl message"
msgstr "Prowl viestin lähetys epäonnistui"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2857,7 +2862,8 @@ msgid ""
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2865,7 +2871,8 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0RC1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Fred L <88com88@gmail.com>, 2024\n"
"Language-Team: French (https://app.transifex.com/sabnzbd/teams/111101/fr/)\n"
@@ -1220,6 +1220,11 @@ msgstr "Échec de l'envoi de la notification macOS"
msgid "Failed to send Prowl message"
msgstr "Échec d'envoi du message Prowl"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr "Échec d'envoi du message Apprise - aucune URLs définies"
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2958,9 +2963,11 @@ msgstr ""
"tâches spécifié"
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
"Supprimer les tâches si l'historique dépasse le nombre de tâches spécifié"
"Supprimer les tâches si l'historique et les archives dépassent le nombre de "
"tâches spécifié"
#: sabnzbd/skintext.py
msgid "Move jobs to the archive after specified number of days"
@@ -2968,8 +2975,11 @@ msgstr ""
"Déplacer les tâches vers les archives après le nombre de jours spécifié"
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgstr "Supprimer les tâches après le nombre de jours spécifié"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
"Supprimer les tâches de l'historique et des archives après le nombre de "
"jours spécifié"
#: sabnzbd/skintext.py
msgid "Move all completed jobs to archive"

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: ION, 2024\n"
"Language-Team: Hebrew (https://app.transifex.com/sabnzbd/teams/111101/he/)\n"
@@ -186,6 +186,8 @@ msgid ""
"server (port 80), possibly an indexer, not a usenet server. You have to fill"
" a usenet server."
msgstr ""
"לא היה ניתן להתחבר אל %s על פתחה %s. נראה כי %s פועל כשרת רשת (פתחה 80), "
"כנראה מדדן, לא שרת Usenet. אתה חייב למלא שרת Usenet."
#: sabnzbd/api.py, sabnzbd/interface.py
msgid "Server address \"%s:%s\" is not valid."
@@ -512,7 +514,7 @@ msgstr "שגיאה גורלית במורידן"
#. Warning message
#: sabnzbd/downloader.py
msgid "%s@%s: Received unknown status code %s for article %s"
msgstr ""
msgstr "%s@%s: קוד בלתי ידוע של מעמד התקבל %s עבור מאמר %s"
#: sabnzbd/downloader.py
msgid "Too many connections to server %s [%s]"
@@ -1088,7 +1090,7 @@ msgstr "וויקי"
#: sabnzbd/newswrapper.py
msgid "Failed to connect: %s %s@%s:%s (%s)"
msgstr ""
msgstr "כישלון בהתחברות: %s %s@%s:%s (%s)"
#. Notification
#: sabnzbd/notifier.py
@@ -1160,6 +1162,11 @@ msgstr "כישלון בשליחת התראת macOS"
msgid "Failed to send Prowl message"
msgstr "כישלון בשליחת הודעת Prowl"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2345,7 +2352,7 @@ msgstr "למחוק את כל הפריטים מהתור?"
#. Delete confirmation popup
#: sabnzbd/skintext.py
msgid "Are you sure you want to remove these jobs?"
msgstr ""
msgstr "האם אתה בטוח שאתה רוצה להסיר עבודות אלו?"
#. Queue page button
#: sabnzbd/skintext.py
@@ -2370,7 +2377,7 @@ msgstr "הסר NZB ומחק קבצים"
#. Checkbox if job should be added to Archive
#: sabnzbd/skintext.py
msgid "Permanently delete (skip archive)"
msgstr ""
msgstr "מחק לצמיתות (דלג על ארכיון)"
#. Caption for missing articles in Queue
#: sabnzbd/skintext.py
@@ -2393,7 +2400,7 @@ msgstr "אפס מכסה כעת"
#: sabnzbd/skintext.py
msgid "Archive"
msgstr ""
msgstr "ארכיון"
#. Button/link hiding History job details
#: sabnzbd/skintext.py
@@ -2418,7 +2425,7 @@ msgstr "הראה הכל"
#. Button showing all archived jobs
#: sabnzbd/skintext.py
msgid "Show Archive"
msgstr ""
msgstr "הראה ארכיון"
#. History table header - Size of the download quota
#: sabnzbd/skintext.py
@@ -2866,27 +2873,29 @@ msgstr "שמור את כל העבודות"
#: sabnzbd/skintext.py
msgid ""
"Move jobs to the archive if the history exceeds specified number of jobs"
msgstr ""
msgstr "העבר עבודות אל הארכיון אם ההיסטוריה חורגת ממספר מצוין של ימים"
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
msgid "Move jobs to the archive after specified number of days"
msgstr ""
msgstr "העבר עבודות אל הארכיון לאחר מספר מצוין של ימים"
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Move all completed jobs to archive"
msgstr ""
msgstr "העבר את כל העבודות השלמות אל הארכיון"
#: sabnzbd/skintext.py
msgid "Delete all completed jobs"
msgstr ""
msgstr "מחק את כל העבודות השלמות"
#: sabnzbd/skintext.py
msgid "Jobs"

View File

@@ -3,7 +3,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Language-Team: Italian (https://app.transifex.com/sabnzbd/teams/111101/it/)\n"
"MIME-Version: 1.0\n"
@@ -1124,6 +1124,11 @@ msgstr ""
msgid "Failed to send Prowl message"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2779,7 +2784,8 @@ msgid ""
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2787,7 +2793,8 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Norwegian Bokmål (https://app.transifex.com/sabnzbd/teams/111101/nb/)\n"
@@ -1151,6 +1151,11 @@ msgstr ""
msgid "Failed to send Prowl message"
msgstr "Klarte ikke å sende Prowl melding"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2849,7 +2854,8 @@ msgid ""
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2857,7 +2863,8 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

@@ -8,7 +8,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2024\n"
"Language-Team: Dutch (https://app.transifex.com/sabnzbd/teams/111101/nl/)\n"
@@ -1210,6 +1210,11 @@ msgstr "Kon macOS notificatie niet verzenden"
msgid "Failed to send Prowl message"
msgstr "Verzenden van Prowl-bericht mislukt"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2937,10 +2942,9 @@ msgstr ""
"opgegeven aantal voltooide downloads overschrijdt."
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
"Verwijder voltooide downloads als de geschiedenis het opgegeven aantal "
"voltooide downloads overschrijdt."
#: sabnzbd/skintext.py
msgid "Move jobs to the archive after specified number of days"
@@ -2948,8 +2952,9 @@ msgstr ""
"Verplaats voltooide downloads naar het archief na het opgegeven aantal dagen"
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgstr "Verwijder voltooide downloads na het opgegeven aantal dagen"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Move all completed jobs to archive"

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Polish (https://app.transifex.com/sabnzbd/teams/111101/pl/)\n"
@@ -1156,6 +1156,11 @@ msgstr ""
msgid "Failed to send Prowl message"
msgstr "Błąd wysyłania wiadomości Prowl"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2860,7 +2865,8 @@ msgid ""
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2868,7 +2874,8 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Portuguese (Brazil) (https://app.transifex.com/sabnzbd/teams/111101/pt_BR/)\n"
@@ -1165,6 +1165,11 @@ msgstr ""
msgid "Failed to send Prowl message"
msgstr "Falha ao enviar mensagem Prowl"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2870,7 +2875,8 @@ msgid ""
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2878,7 +2884,8 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Romanian (https://app.transifex.com/sabnzbd/teams/111101/ro/)\n"
@@ -1181,6 +1181,11 @@ msgstr "Eșuare la trimiterea notificării macOS"
msgid "Failed to send Prowl message"
msgstr "Nu am putu trimite mesajul Prowl"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2889,7 +2894,8 @@ msgid ""
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2897,7 +2903,8 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Russian (https://app.transifex.com/sabnzbd/teams/111101/ru/)\n"
@@ -1151,6 +1151,11 @@ msgstr ""
msgid "Failed to send Prowl message"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2849,7 +2854,8 @@ msgid ""
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2857,7 +2863,8 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Serbian (https://app.transifex.com/sabnzbd/teams/111101/sr/)\n"
@@ -1146,6 +1146,11 @@ msgstr ""
msgid "Failed to send Prowl message"
msgstr "Неуспешно слање Prowl поруке"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2840,7 +2845,8 @@ msgid ""
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2848,7 +2854,8 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

@@ -6,7 +6,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Safihre <safihre@sabnzbd.org>, 2023\n"
"Language-Team: Swedish (https://app.transifex.com/sabnzbd/teams/111101/sv/)\n"
@@ -1150,6 +1150,11 @@ msgstr ""
msgid "Failed to send Prowl message"
msgstr "Misslyckades att skicka Prowlmeddelande"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2849,7 +2854,8 @@ msgid ""
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2857,7 +2863,8 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:49+0000\n"
"Last-Translator: Kangwei Li <lkw20010211@gmail.com>, 2023\n"
"Language-Team: Chinese (China) (https://app.transifex.com/sabnzbd/teams/111101/zh_CN/)\n"
@@ -1139,6 +1139,11 @@ msgstr ""
msgid "Failed to send Prowl message"
msgstr "无法发送 Prowl 消息"
#. Warning message
#: sabnzbd/notifier.py
msgid "Failed to send Apprise message - no URLs defined"
msgstr ""
#. Warning message
#: sabnzbd/notifier.py
msgid "One or more Apprise URLs could not be loaded."
@@ -2822,7 +2827,8 @@ msgid ""
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs if the history exceeds specified number of jobs"
msgid ""
"Delete jobs if the history and archive exceeds specified number of jobs"
msgstr ""
#: sabnzbd/skintext.py
@@ -2830,7 +2836,8 @@ msgid "Move jobs to the archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py
msgid "Delete jobs after specified number of days"
msgid ""
"Delete jobs from the history and archive after specified number of days"
msgstr ""
#: sabnzbd/skintext.py

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0Beta1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Lorenz B, 2024\n"
"Language-Team: German (https://app.transifex.com/sabnzbd/teams/111101/de/)\n"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: SABnzbd-4.3.0RC1\n"
"Project-Id-Version: SABnzbd-4.3.3Beta2\n"
"PO-Revision-Date: 2020-06-27 15:56+0000\n"
"Last-Translator: Petter Ramme, 2024\n"
"Language-Team: Swedish (https://app.transifex.com/sabnzbd/teams/111101/sv/)\n"

View File

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

View File

@@ -1,73 +1,73 @@
# Main requirements
# Note that not all sub-dependencies are listed, but only ones we know could cause trouble
apprise==1.7.6
sabctools==8.1.0
apprise==1.8.1
sabctools==8.2.5
CT3==3.3.3.post1
cffi==1.16.0
cffi==1.17.0
pycparser==2.22
feedparser==6.0.11
configobj==5.0.8
cheroot==10.0.1
six==1.16.0
cherrypy==18.9.0
jaraco.functools==4.0.1
cherrypy==18.10.0
jaraco.functools==4.0.2
jaraco.collections==5.0.0
jaraco.text==3.8.1 # Newer version introduces irrelevant extra dependencies
jaraco.classes==3.4.0
jaraco.context==4.3.0
more-itertools==10.2.0
more-itertools==10.4.0
zc.lockfile==3.0.post1
python-dateutil==2.9.0.post0
tempora==5.5.1
tempora==5.7.0
pytz==2024.1
sgmllib3k==1.0.0
portend==3.2.0
chardet==5.2.0
PySocks==1.7.1
puremagic==1.22
puremagic==1.27
guessit==3.8.0
babelfish==0.6.0
babelfish==0.6.1
rebulk==3.2.0
# Recent cryptography versions require Rust. If you run into issues compiling this
# SABnzbd will also work with older pre-Rust versions such as cryptography==3.3.2
cryptography==42.0.5
cryptography==43.0.0
# We recommend using "orjson" as it is 2x as fast as "ujson". However, it requires
# Rust so SABnzbd works just as well with "ujson" or the Python built in "json" module
ujson==5.9.0
ujson==5.10.0
# Windows system integration
pywin32==306; sys_platform == 'win32'
windows-toasts==1.1.0; sys_platform == 'win32' and python_version > '3.8'
winrt-runtime==2.0.1; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.Data.Xml.Dom==2.0.1; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.Foundation==2.0.1; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.Foundation.Collections==2.0.1; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.UI.Notifications==2.0.1; sys_platform == 'win32' and python_version > '3.8'
windows-toasts==1.2.0; sys_platform == 'win32' and python_version > '3.8'
winrt-runtime==2.1.0; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.Data.Xml.Dom==2.1.0; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.Foundation==2.1.0; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.Foundation.Collections==2.1.0; sys_platform == 'win32' and python_version > '3.8'
winrt-Windows.UI.Notifications==2.1.0; sys_platform == 'win32' and python_version > '3.8'
# macOS system calls
pyobjc-core==10.2; sys_platform == 'darwin'
pyobjc-framework-Cocoa==10.2; sys_platform == 'darwin'
pyobjc-core==10.3.1; sys_platform == 'darwin'
pyobjc-framework-Cocoa==10.3.1; sys_platform == 'darwin'
# Linux notifications
notify2==0.3.1; sys_platform != 'win32' and sys_platform != 'darwin'
# Apprise Requirements
requests==2.31.0
requests==2.32.3
requests-oauthlib==2.0.0
PyYAML==6.0.1
PyYAML==6.0.2
markdown==3.6
paho-mqtt==2.0.0
paho-mqtt==1.6.1 # Pinned, newer versions don't work with AppRise yet
# Requests Requirements
charset_normalizer==3.3.2
idna==3.7
urllib3==2.2.1
certifi==2024.2.2
urllib3==2.2.2
certifi==2024.7.4
oauthlib==3.2.2
PyJWT==2.8.0
blinker==1.8.1
PyJWT==2.9.0
blinker==1.8.2
# Optional support for *nix tray icon.
# Note that pygobject depends on pycairo, which requires pkg-config and cairo headers.

View File

@@ -37,7 +37,7 @@ KERNEL32 = LIBC = MACOSLIBC = None
if os.name == "nt":
WIN32 = True
WIN64 = platform.uname().machine == "AMD64"
WIN64 = platform.uname().machine in ["AMD64", "ARM64"] # includes emulation of X86_64 on Windows ARM64
from sabnzbd.utils.apireg import del_connection_info
try:
@@ -245,8 +245,8 @@ def initialize(pause_downloader=False, clean_up=False, repair=0):
# Set call backs for Config items
cfg.cache_limit.callback(cfg.new_limit)
cfg.cherryhost.callback(cfg.guard_restart)
cfg.cherryport.callback(cfg.guard_restart)
cfg.web_host.callback(cfg.guard_restart)
cfg.web_port.callback(cfg.guard_restart)
cfg.web_dir.callback(cfg.guard_restart)
cfg.web_color.callback(cfg.guard_restart)
cfg.username.callback(cfg.guard_restart)

View File

@@ -54,7 +54,7 @@ from sabnzbd.constants import (
AddNzbFileResult,
PP_LOOKUP,
STAGES,
DEF_TEST_TIMEOUT,
DEF_NETWORKING_TEST_TIMEOUT,
)
import sabnzbd.config as config
import sabnzbd.cfg as cfg
@@ -76,6 +76,7 @@ from sabnzbd.misc import (
change_queue_complete_action,
clean_comma_separated_list,
match_str,
bool_conv,
)
from sabnzbd.filesystem import diskspace, get_ext, clip_path, remove_all, list_scripts, purge_log_files, pathbrowser
from sabnzbd.encoding import xml_name, utob
@@ -180,7 +181,7 @@ def _api_queue_delete(value: str, kwargs: Dict[str, Union[str, List[str]]]) -> b
removed = sabnzbd.NzbQueue.remove_all(kwargs.get("search"))
return report(keyword="", data={"status": bool(removed), "nzo_ids": removed})
elif items := clean_comma_separated_list(value):
delete_all_data = int_conv(kwargs.get("del_files"))
delete_all_data = bool_conv(kwargs.get("del_files"))
removed = sabnzbd.NzbQueue.remove_multiple(items, delete_all_data=delete_all_data)
return report(keyword="", data={"status": bool(removed), "nzo_ids": removed})
else:
@@ -422,8 +423,8 @@ def _api_change_opts(name: str, kwargs: Dict[str, Union[str, List[str]]]) -> byt
def _api_fullstatus(name: str, kwargs: Dict[str, Union[str, List[str]]]) -> bytes:
"""API: full history status"""
status = build_status(
calculate_performance=int_conv(kwargs.get("calculate_performance", 0)),
skip_dashboard=int_conv(kwargs.get("skip_dashboard", 1)),
calculate_performance=bool_conv(kwargs.get("calculate_performance")),
skip_dashboard=bool_conv(kwargs.get("skip_dashboard")),
)
return report(keyword="status", data=status)
@@ -487,18 +488,18 @@ def _api_history(name: str, kwargs: Dict[str, Union[str, List[str]]]) -> bytes:
search = kwargs.get("search")
categories = clean_comma_separated_list(kwargs.get("cat") or kwargs.get("category"))
statuses = clean_comma_separated_list(kwargs.get("status"))
failed_only = int_conv(kwargs.get("failed_only"))
failed_only = bool_conv(kwargs.get("failed_only"))
nzo_ids = clean_comma_separated_list(kwargs.get("nzo_ids"))
archive = True
if name == "delete":
# Only skip archive if specifically requested
if kwargs.get("archive") == "0":
if kwargs.get("archive") == "0" or cfg.disable_archive():
archive = False
special = value.lower()
del_files = bool(int_conv(kwargs.get("del_files")))
del_files = bool_conv(kwargs.get("del_files"))
if special in ("all", "failed", "completed"):
history_db = sabnzbd.get_db_connection()
if special in ("all", "failed"):
@@ -868,9 +869,9 @@ def _api_undefined(name: str, kwargs: Dict[str, Union[str, List[str]]]) -> bytes
def _api_browse(name: str, kwargs: Dict[str, Union[str, List[str]]]) -> bytes:
"""Return tree of local path"""
compact = bool(int_conv(kwargs.get("compact")))
show_files = bool(int_conv(kwargs.get("show_files")))
show_hidden = bool(int_conv(kwargs.get("show_hidden_folders")))
compact = bool_conv(kwargs.get("compact"))
show_files = bool_conv(kwargs.get("show_files"))
show_hidden = bool_conv(kwargs.get("show_hidden_folders"))
if compact:
# Used for typeahead
@@ -1267,7 +1268,7 @@ def test_nntp_server_dict(kwargs: Dict[str, Union[str, List[str]]]) -> Tuple[boo
password = kwargs.get("password", "").strip()
server = kwargs.get("server", "").strip()
connections = int_conv(kwargs.get("connections", 0))
timeout = int_conv(kwargs.get("timeout", DEF_TEST_TIMEOUT))
timeout = int_conv(kwargs.get("timeout", DEF_NETWORKING_TEST_TIMEOUT))
ssl = int_conv(kwargs.get("ssl", 0))
ssl_verify = int_conv(kwargs.get("ssl_verify", 1))
ssl_ciphers = kwargs.get("ssl_ciphers", "").strip()
@@ -1286,7 +1287,7 @@ def test_nntp_server_dict(kwargs: Dict[str, Union[str, List[str]]]) -> Tuple[boo
if not timeout:
# Lower value during new server testing
timeout = DEF_TEST_TIMEOUT
timeout = DEF_NETWORKING_TEST_TIMEOUT
if "*" in password and not password.strip("*"):
# If the password is masked, try retrieving it from the config
@@ -1318,7 +1319,7 @@ def test_nntp_server_dict(kwargs: Dict[str, Union[str, List[str]]]) -> Tuple[boo
if not test_server.addrinfo:
# Try if we can connect on port 80 (so web server), forcing a short timeout
test_server.port = 80
test_server.timeout = DEF_TEST_TIMEOUT
test_server.timeout = DEF_NETWORKING_TEST_TIMEOUT
test_server.request_addrinfo_blocking()
if test_server.addrinfo:
return False, T(
@@ -1384,7 +1385,7 @@ def test_nntp_server_dict(kwargs: Dict[str, Union[str, List[str]]]) -> Tuple[boo
return return_status
def build_status(calculate_performance: int = False, skip_dashboard: int = False) -> Dict[str, Any]:
def build_status(calculate_performance: bool = False, skip_dashboard: bool = False) -> Dict[str, Any]:
# build up header full of basic information
info = build_header(trans_functions=False)

View File

@@ -309,8 +309,8 @@ version_check = OptionNumber("misc", "check_new_rel", 1)
autobrowser = OptionBool("misc", "auto_browser", True)
language = OptionStr("misc", "language", "en")
enable_https_verification = OptionBool("misc", "enable_https_verification", True)
cherryhost = OptionStr("misc", "host", DEF_HOST, validation=validate_host)
cherryport = OptionStr("misc", "port", DEF_PORT)
web_host = OptionStr("misc", "host", DEF_HOST, validation=validate_host)
web_port = OptionStr("misc", "port", DEF_PORT)
https_port = OptionStr("misc", "https_port")
username = OptionStr("misc", "username")
password = OptionPassword("misc", "password")
@@ -456,6 +456,7 @@ wait_for_dfolder = OptionBool("misc", "wait_for_dfolder", False)
rss_filenames = OptionBool("misc", "rss_filenames", False)
api_logging = OptionBool("misc", "api_logging", True)
html_login = OptionBool("misc", "html_login", True)
disable_archive = OptionBool("misc", "disable_archive", False)
warn_dupl_jobs = OptionBool("misc", "warn_dupl_jobs", False)
keep_awake = OptionBool("misc", "keep_awake", True)

View File

@@ -205,7 +205,7 @@ class OptionBool(Option):
def set(self, value: Any):
# Store the value as integer, easier to parse when reading the config.
super().set(sabnzbd.misc.int_conv(value))
super().set(sabnzbd.misc.bool_conv(value))
def __call__(self) -> int:
"""get() replacement"""

View File

@@ -49,7 +49,7 @@ RENAMES_FILE = "__renames__"
ATTRIB_FILE = "SABnzbd_attrib"
REPAIR_REQUEST = "repair-all.sab"
SABCTOOLS_VERSION_REQUIRED = "8.1.0"
SABCTOOLS_VERSION_REQUIRED = "8.2.5"
DB_HISTORY_VERSION = 1
DB_HISTORY_NAME = "history%s.db" % DB_HISTORY_VERSION
@@ -74,8 +74,9 @@ DEF_LOG_ERRFILE = "sabnzbd.error.log"
DEF_LOG_CHERRY = "cherrypy.log"
DEF_ARTICLE_CACHE_DEFAULT = "500M"
DEF_ARTICLE_CACHE_MAX = "1G"
DEF_TIMEOUT = 60
DEF_TEST_TIMEOUT = 5
DEF_NETWORKING_TIMEOUT = 60
DEF_NETWORKING_TEST_TIMEOUT = 5
DEF_NETWORKING_SHORT_TIMEOUT = 3
DEF_SCANRATE = 5
DEF_HTTPS_CERT_FILE = "server.cert"
DEF_HTTPS_KEY_FILE = "server.key"
@@ -100,6 +101,7 @@ SOFT_QUEUE_LIMIT = 0.5
# Percentage of cache to use before adding file to assembler
ASSEMBLER_WRITE_THRESHOLD = 5
NNTP_BUFFER_SIZE = int(800 * KIBI)
NTTP_MAX_BUFFER_SIZE = int(10 * MEBI)
REPAIR_PRIORITY = 3
FORCE_PRIORITY = 2

View File

@@ -35,7 +35,7 @@ from sabnzbd.constants import DB_HISTORY_NAME, STAGES, Status, PP_LOOKUP
from sabnzbd.bpsmeter import this_week, this_month
from sabnzbd.decorators import synchronized
from sabnzbd.encoding import ubtou, utob
from sabnzbd.misc import int_conv, caller_name, opts_to_pp, to_units
from sabnzbd.misc import caller_name, opts_to_pp, to_units, bool_conv
from sabnzbd.filesystem import remove_file, clip_path
DB_LOCK = threading.Lock()
@@ -596,7 +596,7 @@ def unpack_history_info(item: sqlite3.Row) -> Dict[str, Any]:
item["archive"] = bool(item["archive"])
# Retry and retry for failed URL-fetch
item["retry"] = int_conv(item["status"] == Status.FAILED and item["path"] and os.path.exists(item["path"]))
item["retry"] = bool_conv(item["status"] == Status.FAILED and item["path"] and os.path.exists(item["path"]))
if item["report"] == "future":
item["retry"] = True

View File

@@ -198,7 +198,7 @@ class Server:
def reset_article_queue(self):
logging.debug("Resetting article queue for %s", self)
for article in self.article_queue:
sabnzbd.NzbQueue.reset_try_lists(article, remove_fetcher_from_trylist=False)
sabnzbd.NzbQueue.reset_try_lists(article)
self.article_queue = []
def request_addrinfo(self):
@@ -510,8 +510,8 @@ class Downloader(Thread):
# Handle broken articles directly
if not data_view:
if not article.search_new_server():
sabnzbd.NzbQueue.register_article(article, success=False)
article.nzf.nzo.increase_bad_articles_counter("missing_articles")
sabnzbd.NzbQueue.register_article(article, success=False)
return
# Decode and send to article cache
@@ -704,9 +704,14 @@ class Downloader(Thread):
except ssl.SSLWantReadError:
return
except (ConnectionError, ConnectionAbortedError):
# The ConnectionAbortedError is thrown by sabctools in case of fatal SSL-layer problems
# The ConnectionAbortedError is also thrown by sabctools in case of fatal SSL-layer problems
self.__reset_nw(nw, "Server closed connection", wait=False)
return
except BufferError:
# The BufferError is thrown when exceeding maximum buffer size
# Make sure to discard the article
self.__reset_nw(nw, "Maximum data buffer size exceeded", wait=False, retry_article=False)
return
article = nw.article
server = nw.server
@@ -960,14 +965,9 @@ class Downloader(Thread):
self.decode(nw.article)
nw.article.tries = 0
else:
# Retry again with the same server
logging.debug(
"Re-adding article %s from %s to server %s",
nw.article.article,
nw.article.nzf.filename,
nw.article.fetcher,
)
nw.article.fetcher.article_queue.append(nw.article)
# Allow all servers again on this server
# Do not use the article_queue, as the server could already have been disabled when we get here!
sabnzbd.NzbQueue.reset_try_lists(nw.article)
# Reset connection object
nw.hard_reset(wait)

View File

@@ -25,7 +25,7 @@ import socket
import time
import urllib.error
import urllib.request
from typing import Callable
from typing import Callable, Optional
import socks
@@ -33,9 +33,10 @@ import sabnzbd
import sabnzbd.cfg
from sabnzbd.encoding import ubtou
from sabnzbd.happyeyeballs import happyeyeballs, family_type
from sabnzbd.constants import DEF_NETWORKING_SHORT_TIMEOUT
def timeout(max_timeout: float):
def timeout(max_timeout: int):
"""Timeout decorator, parameter in seconds."""
def timeout_decorator(item: Callable) -> Callable:
@@ -56,29 +57,29 @@ def timeout(max_timeout: float):
return timeout_decorator
@timeout(3.0)
@timeout(DEF_NETWORKING_SHORT_TIMEOUT)
def addresslookup(myhost):
return socket.getaddrinfo(myhost, 80)
@timeout(3.0)
@timeout(DEF_NETWORKING_SHORT_TIMEOUT)
def addresslookup4(myhost):
return socket.getaddrinfo(myhost, 80, socket.AF_INET)
@timeout(3.0)
@timeout(DEF_NETWORKING_SHORT_TIMEOUT)
def addresslookup6(myhost):
return socket.getaddrinfo(myhost, 80, socket.AF_INET6)
def active_socks5_proxy():
def active_socks5_proxy() -> Optional[str]:
"""Return the active proxy"""
if socket.socket == socks.socksocket:
return "%s:%s" % socks.socksocket.default_proxy[1:3]
return None
def dnslookup():
def dnslookup() -> bool:
"""Perform a basic DNS lookup"""
start = time.time()
try:
@@ -90,7 +91,7 @@ def dnslookup():
return result
def local_ipv4():
def local_ipv4() -> Optional[str]:
try:
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s_ipv4:
# Option: use 100.64.1.1 (IANA-Reserved IPv4 Prefix for Shared Address Space)
@@ -103,12 +104,17 @@ def local_ipv4():
return ipv4
def public_ip(family=socket.AF_UNSPEC):
def public_ip(family: int = socket.AF_UNSPEC) -> Optional[str]:
"""
Reports the client's public IP address (IPv4 or IPv6, if specified by family), as reported by selftest host
"""
start = time.time()
if resolvehostaddress := happyeyeballs(sabnzbd.cfg.selftest_host(), port=443, family=family):
if resolvehostaddress := happyeyeballs(
sabnzbd.cfg.selftest_host(),
port=443,
timeout=DEF_NETWORKING_SHORT_TIMEOUT,
family=family,
):
resolvehostip = resolvehostaddress.ipaddress
else:
logging.debug("Error resolving my IP address: resolvehost not found")
@@ -126,7 +132,7 @@ def public_ip(family=socket.AF_UNSPEC):
req = urllib.request.Request(resolveurl)
req.add_header("Host", sabnzbd.cfg.selftest_host())
req.add_header("User-Agent", "SABnzbd/%s" % sabnzbd.__version__)
with urllib.request.urlopen(req, timeout=2) as open_req:
with urllib.request.urlopen(req, timeout=DEF_NETWORKING_SHORT_TIMEOUT) as open_req:
client_ip = ubtou(open_req.read().strip())
# Make sure it's a valid IPv4 or IPv6 address
@@ -146,11 +152,11 @@ def public_ip(family=socket.AF_UNSPEC):
return client_ip
def public_ipv4():
def public_ipv4() -> Optional[str]:
return public_ip(family=socket.AF_INET)
def local_ipv6():
def local_ipv6() -> Optional[str]:
"""
return IPv6 address on local LAN interface. So a first check if there is IPv6 connectivity
"""
@@ -167,8 +173,8 @@ def local_ipv6():
return ipv6_address
def public_ipv6():
if local_address := local_ipv6():
def public_ipv6() -> Optional[str]:
if (local_address := local_ipv6()) and not sabnzbd.misc.ip_in_subnet(local_address, "fe80::/10"):
if public_address := public_ip(family=socket.AF_INET6):
return public_address
elif not sabnzbd.misc.is_lan_addr(local_address):

View File

@@ -34,7 +34,7 @@ from typing import Tuple, Union, Optional
from more_itertools import roundrobin
import sabnzbd.cfg as cfg
from sabnzbd.constants import DEF_TIMEOUT
from sabnzbd.constants import DEF_NETWORKING_TIMEOUT
from sabnzbd.decorators import cache_maintainer
# How long to delay between connection attempts? The RFC suggests 250ms, but this is
@@ -118,7 +118,12 @@ def do_socket_connect(result_queue: queue.Queue, addrinfo: AddrInfo, timeout: in
@cache_maintainer(clear_time=10)
@functools.lru_cache(maxsize=None)
def happyeyeballs(host: str, port: int, timeout: int = DEF_TIMEOUT, family=socket.AF_UNSPEC) -> Optional[AddrInfo]:
def happyeyeballs(
host: str,
port: int,
timeout: int = DEF_NETWORKING_TIMEOUT,
family=socket.AF_UNSPEC,
) -> Optional[AddrInfo]:
"""Return the fastest result of getaddrinfo() based on RFC 6555/8305 (Happy Eyeballs),
including IPv6 addresses if desired. Returns None in case no addresses were returned
by getaddrinfo or if no connection could be made to any of the addresses.

View File

@@ -80,7 +80,7 @@ from sabnzbd.constants import (
GUESSIT_SORT_TYPES,
VALID_NZB_FILES,
VALID_ARCHIVES,
DEF_TEST_TIMEOUT,
DEF_NETWORKING_TEST_TIMEOUT,
)
from sabnzbd.lang import list_languages
from sabnzbd.api import (
@@ -434,6 +434,7 @@ class MainPage:
info["cpumodel"] = get_cpu_name()
info["cpusimd"] = sabnzbd.decoder.SABCTOOLS_SIMD
info["docker"] = "Docker" if sabnzbd.DOCKER else ""
# Have logout only with HTML and if inet=5, only when we are external
info["have_logout"] = (
@@ -577,7 +578,7 @@ class Wizard:
def get_access_info():
"""Build up a list of url's that sabnzbd can be accessed from"""
# Access_url is used to provide the user a link to SABnzbd depending on the host
cherryhost = cfg.cherryhost()
web_host = cfg.web_host()
host = socket.gethostname().lower()
logging.info("hostname is", host)
socks = [host]
@@ -587,7 +588,7 @@ def get_access_info():
except:
addresses = []
if cherryhost == "0.0.0.0":
if web_host == "0.0.0.0":
# Grab a list of all ips for the hostname
for addr in addresses:
address = addr[4][0]
@@ -595,7 +596,7 @@ def get_access_info():
if ":" not in address and address not in socks:
socks.append(address)
socks.insert(0, "localhost")
elif cherryhost == "::":
elif web_host == "::":
# Grab a list of all ips for the hostname
for addr in addresses:
address = addr[4][0]
@@ -605,8 +606,8 @@ def get_access_info():
if address not in socks:
socks.append(address)
socks.insert(0, "localhost")
elif cherryhost:
socks = [cherryhost]
elif web_host:
socks = [web_host]
# Add the current requested URL as the base
access_url = urllib.parse.urljoin(cherrypy.request.base, cfg.url_base())
@@ -617,9 +618,9 @@ def get_access_info():
if cfg.enable_https() and cfg.https_port():
url = "https://%s:%s%s" % (sock, cfg.https_port(), cfg.url_base())
elif cfg.enable_https():
url = "https://%s:%s%s" % (sock, cfg.cherryport(), cfg.url_base())
url = "https://%s:%s%s" % (sock, cfg.web_port(), cfg.url_base())
else:
url = "http://%s:%s%s" % (sock, cfg.cherryport(), cfg.url_base())
url = "http://%s:%s%s" % (sock, cfg.web_port(), cfg.url_base())
urls.append(url)
# Return a unique list
@@ -857,6 +858,7 @@ SPECIAL_BOOL_LIST = (
"empty_postproc",
"new_nzb_on_failure",
"html_login",
"disable_archive",
"wait_for_dfolder",
"enable_broadcast",
"warn_dupl_jobs",
@@ -1143,7 +1145,9 @@ def handle_server(kwargs, root=None, new_svr=False):
kwargs["connections"] = "1"
if kwargs.get("enable") == "1":
if not happyeyeballs(host, int_conv(port), int_conv(kwargs.get("timeout"), default=DEF_TEST_TIMEOUT)):
if not happyeyeballs(
host, int_conv(port), int_conv(kwargs.get("timeout"), default=DEF_NETWORKING_TEST_TIMEOUT)
):
return badParameterResponse(T('Server address "%s:%s" is not valid.') % (host, port), ajax)
# Default server name is just the host name
@@ -2155,8 +2159,10 @@ class ConfigNotify:
for section in NOTIFY_OPTIONS:
for option in NOTIFY_OPTIONS[section]:
# Use get_string to make sure lists are displayed correctly
conf[option] = config.get_config(section, option).get_string()
conf[option] = config.get_config(section, option)()
# Use get_string to make sure lists are displayed correctly
conf["email_to"] = cfg.email_to.get_string()
return template_filtered_response(
file=os.path.join(sabnzbd.WEB_DIR_CONFIG, "config_notify.tmpl"),

View File

@@ -30,6 +30,7 @@ from typing import Dict
import sabctools
import sabnzbd
from sabnzbd.constants import DEF_NETWORKING_SHORT_TIMEOUT
from sabnzbd.happyeyeballs import happyeyeballs, family_type
TEST_HOSTNAME = "sabnzbd.org"
@@ -37,7 +38,6 @@ TEST_PORT = 443
TEST_FILE = "/tests/internetspeed/100MB.bin"
TEST_FILE_SIZE = 100 * 1024 * 1024
TEST_REQUEST = f"GET {TEST_FILE} HTTP/1.1\nHost: {TEST_HOSTNAME}\nUser-Agent: SABnzbd/{sabnzbd.__version__}\n\n"
SOCKET_TIMEOUT = 3
BUFFER_SIZE = 5 * 1024 * 1024 # Each connection will allocate its own buffer, so mind the memory usage!
NR_CONNECTIONS = 5
@@ -75,33 +75,45 @@ def internetspeed_worker(secure_sock: ssl.SSLSocket, socket_speed: Dict[ssl.SSLS
pass
def internetspeed_interal(test_time_limit: int = TIME_LIMIT, family: int = socket.AF_UNSPEC) -> float:
def internetspeed_interal(family: int = socket.AF_UNSPEC) -> float:
"""Measure internet speed from a test-download using our optimized SSL-code"""
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
socket_speed = {}
try:
addrinfo = happyeyeballs(TEST_HOSTNAME, TEST_PORT, SOCKET_TIMEOUT, family)
if not (addrinfo := happyeyeballs(TEST_HOSTNAME, TEST_PORT, DEF_NETWORKING_SHORT_TIMEOUT, family)):
# no addrinfo from happyeyeballs, so no connection was possible
return 0.0 # no speed at all
for _ in range(NR_CONNECTIONS):
sock = socket.socket(addrinfo.family, addrinfo.type)
sock.settimeout(SOCKET_TIMEOUT)
sock.settimeout(DEF_NETWORKING_SHORT_TIMEOUT)
sock.connect(addrinfo.sockaddr)
secure_sock = context.wrap_socket(sock, server_hostname=TEST_HOSTNAME)
secure_sock.setblocking(False)
socket_speed[secure_sock] = 0
for secure_sock in socket_speed:
threading.Thread(target=internetspeed_worker, args=(secure_sock, socket_speed), daemon=True).start()
threading.Thread(
target=internetspeed_worker,
args=(secure_sock, socket_speed),
daemon=True,
).start()
except Exception:
logging.info("Internet Bandwidth connection failure", exc_info=True)
return 0.0
# We let the workers finish
time.sleep(test_time_limit + 0.5)
time.sleep(TIME_LIMIT + 0.5)
speed = sum(socket_speed.values()) / 1024 / 1024
logging.debug("Internet Bandwidth (%s) = %.2f MB/s - %.2f Mbps", family_type(family), speed, speed * 8.05)
logging.debug(
"Internet Bandwidth (%s) = %.2f MB/s - %.2f Mbps",
family_type(family),
speed,
speed * 8.05,
)
return speed

View File

@@ -167,10 +167,9 @@ def calc_age(date: datetime.datetime, trans: bool = False) -> str:
def safe_lower(txt: Any) -> str:
"""Return lowercased string. Return '' for None"""
if txt:
if txt := str_conv(txt):
return txt.lower()
else:
return ""
return ""
def is_none(inp: Any) -> bool:
@@ -219,17 +218,18 @@ def cat_pp_script_sanitizer(
script: Optional[str] = None,
) -> Tuple[Optional[Union[int, str]], Optional[str], Optional[str]]:
"""Basic sanitizer from outside input to a bit more predictable values"""
# * and Default are valid values
if safe_lower(cat) in ("", "none"):
cat = None
# Cannot use "not pp" because pp can also be 0
if pp in ("", "-1"):
if safe_lower(pp) in ("", "-1", "none"):
pp = None
# Check for valid script is performed in NzbObject init
if not script or script.lower() == "default":
if not script or safe_lower(script) == "default":
script = None
if not cat or cat.lower() in ("default", "*"):
cat = None
return cat, pp, script
@@ -281,7 +281,7 @@ def cat_to_opts(cat, pp=None, script=None, priority=None) -> Tuple[str, int, str
def pp_to_opts(pp: Optional[int]) -> Tuple[bool, bool, bool]:
"""Convert numeric processing options to (repair, unpack, delete)"""
# Convert the pp to an int
pp = sabnzbd.interface.int_conv(pp)
pp = int_conv(pp)
if pp == 0:
return False, False, False
if pp == 1:
@@ -882,7 +882,18 @@ def format_time_string(seconds: float) -> str:
return " ".join(completestr)
def int_conv(value: Any, default: Any = 0) -> int:
def str_conv(value: Any, default: str = "") -> str:
"""Safe conversion to str (None will be converted to empty string)
Returns empty string or requested default value"""
if value is None:
return default
try:
return str(value)
except:
return default
def int_conv(value: Any, default: int = 0) -> int:
"""Safe conversion to int (can handle None)
Returns 0 or requested default value"""
try:
@@ -891,6 +902,12 @@ def int_conv(value: Any, default: Any = 0) -> int:
return default
def bool_conv(value: Any) -> bool:
"""Safe conversion to bool (can handle None)
Returns False in case of None or non-convertable value"""
return bool(int_conv(value))
def create_https_certificates(ssl_cert, ssl_key):
"""Create self-signed HTTPS certificates and store in paths 'ssl_cert' and 'ssl_key'"""
try:

View File

@@ -30,14 +30,14 @@ from typing import Optional, Tuple, Union
import sabnzbd
import sabnzbd.cfg
from sabnzbd.constants import DEF_TIMEOUT, NNTP_BUFFER_SIZE
from sabnzbd.constants import DEF_NETWORKING_TIMEOUT, NNTP_BUFFER_SIZE, NTTP_MAX_BUFFER_SIZE
from sabnzbd.encoding import utob, ubtou
from sabnzbd.happyeyeballs import AddrInfo
from sabnzbd.decorators import synchronized, DOWNLOADER_LOCK
from sabnzbd.misc import int_conv
# Set pre-defined socket timeout
socket.setdefaulttimeout(DEF_TIMEOUT)
socket.setdefaulttimeout(DEF_NETWORKING_TIMEOUT)
class NNTPPermanentError(Exception):
@@ -230,6 +230,10 @@ class NewsWrapper:
def increase_data_buffer(self):
"""Resize the buffer in the extremely unlikely case that it overflows"""
# Sanity check before we go any further
if len(self.data) > NTTP_MAX_BUFFER_SIZE:
raise BufferError("Maximum data buffer size exceeded")
# Input needs to be integer, floats don't work
new_buffer = sabctools.bytearray_malloc(len(self.data) + NNTP_BUFFER_SIZE // 2)
new_buffer[: len(self.data)] = self.data

View File

@@ -338,6 +338,10 @@ def send_apprise(title, msg, notification_type, force=False, test=None):
# Get a list of tags that are set to use the common list
if target := get_targets(notification_type, "apprise"):
if target is True:
if not urls:
# Nothing to notify
logging.warning(T("Failed to send Apprise message - no URLs defined"))
return ""
# Use default list
apobj.add(urls)
elif not apobj.add(target):

View File

@@ -873,11 +873,10 @@ class NzbQueue:
def stop_idle_jobs(self):
"""Detect jobs that have zero files left and send them to post processing"""
# Only check servers that are active
active_servers = [server for server in sabnzbd.Downloader.servers[:] if server.active]
nr_servers = len(active_servers)
active_servers = set(server for server in sabnzbd.Downloader.servers[:] if server.active)
empty = []
if nr_servers <= 0:
if len(active_servers) <= 0:
logging.debug("Skipping stop_idle_jobs because no servers are active")
return
@@ -888,18 +887,19 @@ class NzbQueue:
# Stall prevention by checking if all servers are in the trylist
# This is a CPU-cheaper alternative to prevent stalling
if len(nzo.try_list) >= nr_servers:
if nzo.all_servers_in_try_list(active_servers):
# Maybe the NZF's need a reset too?
for nzf in nzo.files:
if nzo.removed_from_queue:
break
if len(nzf.try_list) >= nr_servers:
if nzf.all_servers_in_try_list(active_servers):
# Check for articles where all active servers have already been tried
for article in nzf.articles[:]:
if article.all_servers_in_try_list(active_servers):
sabnzbd.NzbQueue.register_article(article, success=False)
logging.debug("Removing article %s with bad trylist in file %s", article, nzf.filename)
nzo.increase_bad_articles_counter("missing_articles")
sabnzbd.NzbQueue.register_article(article, success=False)
logging.info("Resetting bad trylist for file %s in job %s", nzf.filename, nzo.final_name)
nzf.reset_try_list()

View File

@@ -129,13 +129,10 @@ class TryList:
with TRYLIST_LOCK:
return server in self.try_list
def all_servers_in_try_list(self, servers: List[Server]) -> bool:
def all_servers_in_try_list(self, all_servers: Set[Server]) -> bool:
"""Check if all servers have been tried"""
with TRYLIST_LOCK:
for server in servers:
if server not in self.try_list:
return False
return True
return all_servers.issubset(self.try_list)
def add_to_try_list(self, server: Server):
"""Register server as having been tried already"""
@@ -836,8 +833,9 @@ class NzbObject(TryList):
self.password = self.meta.get("password", [None])[0]
# Check if we expect propagation delay
if (propagation_delay := self.avg_stamp + float(cfg.propagation_delay() * 60)) > time.time():
self.propagation_delay = propagation_delay
if propagation_delay := cfg.propagation_delay():
if (propagation_delay := self.avg_stamp + float(propagation_delay * 60)) > time.time():
self.propagation_delay = propagation_delay
# Run user pre-queue script if set and valid
if not reuse and make_script_path(cfg.pre_script()):
@@ -1594,7 +1592,8 @@ class NzbObject(TryList):
@synchronized(NZO_LOCK)
def increase_bad_articles_counter(self, bad_article_type: str):
"""Record information about bad articles"""
"""Record information about bad articles. Should be called before
register_article, which triggers the availability check."""
if bad_article_type not in self.nzo_info:
self.nzo_info[bad_article_type] = 0
self.nzo_info[bad_article_type] += 1

View File

@@ -518,8 +518,8 @@ class SABnzbdDelegate(NSObject):
self.setMenuTitle_("\n\n%s\n" % (T("Stopping...")))
def restartSafeHost_(self, sender):
sabnzbd.cfg.cherryhost.set("127.0.0.1")
sabnzbd.cfg.cherryport.set("8080")
sabnzbd.cfg.web_host.set("127.0.0.1")
sabnzbd.cfg.web_port.set("8080")
sabnzbd.cfg.enable_https.set(False)
sabnzbd.config.save_config()
self.setMenuTitle_("\n\n%s\n" % (T("Stopping...")))

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