diff --git a/interfaces/Config/templates/config_server.tmpl b/interfaces/Config/templates/config_server.tmpl index feddc6e..f786407 100644 --- a/interfaces/Config/templates/config_server.tmpl +++ b/interfaces/Config/templates/config_server.tmpl @@ -104,6 +104,11 @@ $T('srv-explain-send_group')
+ + + $T('explain-required') +
+
$T('explain-optional') @@ -226,6 +231,11 @@ ${helpuri}advanced/ssl-ciphers
+ + /> + $T('explain-required') +
+
/> $T('explain-optional') diff --git a/sabnzbd/config.py b/sabnzbd/config.py index bc49b7c..ddcc0cf 100644 --- a/sabnzbd/config.py +++ b/sabnzbd/config.py @@ -409,6 +409,7 @@ class ConfigServer: self.ssl_verify = OptionNumber(name, "ssl_verify", 2, add=False) self.ssl_ciphers = OptionStr(name, "ssl_ciphers", add=False) self.enable = OptionBool(name, "enable", True, add=False) + self.required = OptionBool(name, "required", False, add=False) self.optional = OptionBool(name, "optional", False, add=False) self.retention = OptionNumber(name, "retention", 0, add=False) self.expire_date = OptionStr(name, "expire_date", add=False) @@ -442,6 +443,7 @@ class ConfigServer: "ssl_ciphers", "send_group", "enable", + "required", "optional", "retention", "expire_date", @@ -476,6 +478,7 @@ class ConfigServer: output_dict["ssl_verify"] = self.ssl_verify() output_dict["ssl_ciphers"] = self.ssl_ciphers() output_dict["enable"] = self.enable() + output_dict["required"] = self.required() output_dict["optional"] = self.optional() output_dict["retention"] = self.retention() output_dict["expire_date"] = self.expire_date() diff --git a/sabnzbd/downloader.py b/sabnzbd/downloader.py index 74dfcff..e9ddf81 100644 --- a/sabnzbd/downloader.py +++ b/sabnzbd/downloader.py @@ -73,6 +73,7 @@ class Server: "ssl", "ssl_verify", "ssl_ciphers", + "required", "optional", "retention", "send_group", @@ -109,6 +110,7 @@ class Server: send_group, username=None, password=None, + required=False, optional=False, retention=0, ): @@ -125,6 +127,7 @@ class Server: self.ssl: bool = ssl self.ssl_verify: int = ssl_verify self.ssl_ciphers: str = ssl_ciphers + self.required: bool = required self.optional: bool = optional self.retention: int = retention self.send_group: bool = send_group @@ -312,6 +315,7 @@ class Downloader(Thread): ssl_ciphers = srv.ssl_ciphers() username = srv.username() password = srv.password() + required = srv.required() optional = srv.optional() retention = int(srv.retention() * 24 * 3600) # days ==> seconds send_group = srv.send_group() @@ -344,6 +348,7 @@ class Downloader(Thread): send_group, username, password, + required, optional, retention, ) @@ -473,12 +478,16 @@ class Downloader(Thread): if server.errormsg != errormsg: server.errormsg = errormsg logging.warning(errormsg) - logging.warning(T("Server %s will be ignored for %s minutes"), server.host, _PENALTY_TIMEOUT) + if not server.required: + logging.warning(T("Server %s will be ignored for %s minutes"), server.host, _PENALTY_TIMEOUT) # Not fully the same as the code below for optional servers server.bad_cons = 0 - server.deactivate() - self.plan_server(server, _PENALTY_TIMEOUT) + if server.required: + sabnzbd.Scheduler.plan_required_server_resume() + else: + server.deactivate() + self.plan_server(server, _PENALTY_TIMEOUT) # Optional and active server had too many problems. # Disable it now and send a re-enable plan to the scheduler @@ -835,12 +844,17 @@ class Downloader(Thread): penalty = _PENALTY_UNKNOWN block = True if block or (penalty and server.optional): + retry_article = False if server.active: - server.deactivate() - if penalty and (block or server.optional): - self.plan_server(server, penalty) - # Note that the article is discard for this server - self.__reset_nw(nw, retry_article=False, send_quit=True) + if server.required: + sabnzbd.Scheduler.plan_required_server_resume() + retry_article = True + else: + server.deactivate() + if penalty and (block or server.optional): + self.plan_server(server, penalty) + # Note that the article is discard for this server if the server is not required + self.__reset_nw(nw, retry_article=retry_article, send_quit=True) continue except: logging.error( diff --git a/sabnzbd/interface.py b/sabnzbd/interface.py index 099937f..7d54b43 100644 --- a/sabnzbd/interface.py +++ b/sabnzbd/interface.py @@ -1234,7 +1234,7 @@ def handle_server(kwargs, root=None, new_svr=False): if new_svr: server = unique_svr_name(server) - for kw in ("ssl", "send_group", "enable", "optional"): + for kw in ("ssl", "send_group", "enable", "required", "optional"): if kw not in kwargs.keys(): kwargs[kw] = None if svr and not new_svr: diff --git a/sabnzbd/scheduler.py b/sabnzbd/scheduler.py index 9b5cefd..055ed7a 100644 --- a/sabnzbd/scheduler.py +++ b/sabnzbd/scheduler.py @@ -391,6 +391,11 @@ class Scheduler: self.__check_diskspace, "check_diskspace", 5 * 60, 9 * 60, "threaded", args=[full_dir, required_space] ) + def plan_required_server_resume(self, interval: int = 5): + """Create task for resuming downloading""" + if not sabnzbd.Downloader.paused: + self.plan_resume(interval) + def cancel_resume_task(self): """Cancel the current auto resume task""" if self.resume_task: diff --git a/sabnzbd/skintext.py b/sabnzbd/skintext.py index 3f7c640..5d329a7 100644 --- a/sabnzbd/skintext.py +++ b/sabnzbd/skintext.py @@ -644,6 +644,10 @@ SKIN_TEXT = { "ssl_verify-strict": TT("Strict"), "srv-priority": TT("Priority"), #: Server priority "explain-svrprio": TT("0 is highest priority, 100 is the lowest priority"), #: Explain server priority + "srv-required": TT("Required"), #: Server required tickbox + "explain-required": TT( + "In case of connection failures, the download queue will be paused for a few minutes instead of skipping this server" + ), #: Explain server required tickbox "srv-optional": TT("Optional"), #: Server optional tickbox "explain-optional": TT( "For unreliable servers, will be ignored longer in case of failures"