Compare commits

...

10 Commits

Author SHA1 Message Date
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
17 changed files with 47 additions and 42 deletions

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

@@ -1,13 +1,15 @@
Release Notes - SABnzbd 4.3.3 Beta 2
Release Notes - SABnzbd 4.3.3
=========================================================
This is the third bug fix release of SABnzbd 4.3.0.
## Bug fixes and changes since 4.3.2
* Jobs could get stuck at 99%.
* 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.

View File

@@ -2,7 +2,7 @@
# Note that not all sub-dependencies are listed, but only ones we know could cause trouble
pyinstaller==5.13.2
packaging==24.1
pyinstaller-hooks-contrib==2024.7
pyinstaller-hooks-contrib==2024.8
altgraph==0.17.4
wrapt==1.16.0
setuptools==72.1.0
@@ -10,10 +10,10 @@ setuptools==72.1.0
# Required on 32bit Windows, exclude it based on Python-version
importlib_metadata==8.2.0; python_version < '3.10'
importlib_resources==6.4.0; python_version < '3.10'
zipp==3.19.2; 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.6; python_version > '3.8'
orjson==3.10.7; python_version > '3.8'
# For the Windows build
pefile==2023.2.7; sys_platform == 'win32'

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>

View File

@@ -30,7 +30,7 @@
<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-01" type="stable"/>
<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"/>

View File

@@ -3,7 +3,7 @@
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
@@ -15,7 +15,7 @@ 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.3.0
more-itertools==10.4.0
zc.lockfile==3.0.post1
python-dateutil==2.9.0.post0
tempora==5.7.0
@@ -24,7 +24,7 @@ sgmllib3k==1.0.0
portend==3.2.0
chardet==5.2.0
PySocks==1.7.1
puremagic==1.26
puremagic==1.27
guessit==3.8.0
babelfish==0.6.1
rebulk==3.2.0
@@ -56,7 +56,7 @@ notify2==0.3.1; sys_platform != 'win32' and sys_platform != 'darwin'
# Apprise Requirements
requests==2.32.3
requests-oauthlib==2.0.0
PyYAML==6.0.1
PyYAML==6.0.2
markdown==3.6
paho-mqtt==1.6.1 # Pinned, newer versions don't work with AppRise yet

View File

@@ -101,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

@@ -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

@@ -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"] = (

View File

@@ -30,7 +30,7 @@ from typing import Optional, Tuple, Union
import sabnzbd
import sabnzbd.cfg
from sabnzbd.constants import DEF_NETWORKING_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
@@ -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

@@ -898,8 +898,8 @@ class NzbQueue:
for article in nzf.articles[:]:
if article.all_servers_in_try_list(active_servers):
logging.debug("Removing article %s with bad trylist in file %s", article, nzf.filename)
sabnzbd.NzbQueue.register_article(article, success=False)
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

@@ -1592,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

@@ -6,5 +6,5 @@
# You MUST use double quotes (so " and not ')
# Do not forget to update the appdata file for every major release!
__version__ = "4.3.3Beta2"
__version__ = "4.3.3"
__baseline__ = "unknown"

View File

@@ -3,7 +3,7 @@ pytest==7.4.4
setuptools
selenium
requests
pyfakefs>=5.4.0
pyfakefs>=5.6.0
werkzeug<2.1.0 # Breaks httpbin in newer versions
pytest-httpbin
pytest-httpserver

View File

@@ -912,11 +912,9 @@ class TestCreateAllDirs(ffs.TestCase, PermissionCheckerHelper):
def _permissions_runner(self, test_base, perms_base="0700", apply_permissions=True):
# Create base directory and set the base permissions
perms_base_int = int(perms_base, 8)
self.fs.create_dir(test_base, perms_base_int)
self.fs.create_dir(test_base, perms_base_int, apply_umask=False)
assert os.path.exists(test_base) is True
# Account for pyfakefs (>= 5.4.0) always applying the fake fs umask when creating dirs
perms_base_int_umasked = perms_base_int & ~self.fs.umask
self.assert_dir_perms(test_base, perms_base_int_umasked)
self.assert_dir_perms(test_base, perms_base_int)
# Create directories with permissions
new_dir = os.path.join(test_base, "se 1", "ep1")
@@ -930,7 +928,7 @@ class TestCreateAllDirs(ffs.TestCase, PermissionCheckerHelper):
# Get the current permissions, since os.mkdir masks that out
perms_test_int = int("0777", 8) & ~sabnzbd.ORG_UMASK
self.assert_dir_perms(new_dir, perms_test_int)
self.assert_dir_perms(test_base, perms_base_int_umasked)
self.assert_dir_perms(test_base, perms_base_int)
class TestSetPermissionsWin(ffs.TestCase):
@@ -947,9 +945,7 @@ class TestSetPermissions(ffs.TestCase, PermissionCheckerHelper):
self.setUpPyfakefs()
self.fs.path_separator = "/"
self.fs.is_case_sensitive = True
# All-permissive umask as a workaround for changes in pyfakefs (>= 5.4.0),
# causing it to always take the umask into account when creating dirs
self.fs.umask = int("0000", 8) # rwxrwxrwx
self.fs.umask = int("0022", 8) # rwxr-xr-x
def _runner(self, perms_before_test):
"""
@@ -970,7 +966,7 @@ class TestSetPermissions(ffs.TestCase, PermissionCheckerHelper):
# Setup and verify fake dir
test_dir = "/test"
self.fs.create_dir(test_dir, perms_before_test)
self.fs.create_dir(test_dir, perms_before_test, apply_umask=False)
assert os.path.exists(test_dir) is True
self.assert_dir_perms(test_dir, perms_before_test)
@@ -987,10 +983,10 @@ class TestSetPermissions(ffs.TestCase, PermissionCheckerHelper):
# Create the folder, so it has the expected permissions
if not os.path.exists(basefolder):
try:
self.fs.create_dir(basefolder, perms_before_test)
self.fs.create_dir(basefolder, perms_before_test, apply_umask=False)
except PermissionError:
ffs.set_uid(0)
self.fs.create_file(file, perms_before_test)
self.fs.create_file(file, perms_before_test, apply_umask=False)
assert os.path.exists(basefolder) is True
self.assert_dir_perms(basefolder, perms_before_test)
@@ -1001,10 +997,10 @@ class TestSetPermissions(ffs.TestCase, PermissionCheckerHelper):
# Then, create the file
try:
self.fs.create_file(file, file_perms_before_test)
self.fs.create_file(file, file_perms_before_test, apply_umask=False)
except PermissionError:
ffs.set_uid(0)
self.fs.create_file(file, file_perms_before_test)
self.fs.create_file(file, file_perms_before_test, apply_umask=False)
assert os.path.exists(file) is True
assert stat.filemode(os.stat(file).st_mode)[1:] == stat.filemode(file_perms_before_test)[1:]