diff --git a/news/sabnzbd/Makefile b/news/sabnzbd/Makefile index b33a4a1d292a..d20168e911e9 100644 --- a/news/sabnzbd/Makefile +++ b/news/sabnzbd/Makefile @@ -1,86 +1,87 @@ PORTNAME= sabnzbd DISTVERSION= 4.0.2 +PORTREVISION= 1 CATEGORIES= news MASTER_SITES= https://github.com/sabnzbd/sabnzbd/releases/download/${DISTVERSION}/ DISTNAME= SABnzbd-${DISTVERSION}-src MAINTAINER= james@french.id.au COMMENT= Web-interface based binary newsgrabber in python, with nzb support WWW= https://sabnzbd.org/ LICENSE= BSD2CLAUSE BSD3CLAUSE GPLv2+ ISCL MIT PSFL LICENSE_COMB= multi RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}cheetah3>=0:devel/py-cheetah3@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}cherrypy>=8.9.1:www/py-cherrypy@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}cheroot>=0:www/py-cheroot@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}chardet>=0:textproc/py-chardet@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}configobj>=0:devel/py-configobj@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}feedparser>=6.0.0:textproc/py-feedparser@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}portend>=0:net/py-portend@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}sqlite3>=0:databases/py-sqlite3@${PY_FLAVOR} \ - ${PYTHON_PKGNAMEPREFIX}sabctools>=7.1.0<7.1.0_99:news/py-sabctools@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}sabctools>=7.1.0<7.1.1_99:news/py-sabctools@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}guessit>0:multimedia/py-guessit@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}puremagic>0:sysutils/py-puremagic@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}pysocks>0:net/py-pysocks@${PY_FLAVOR} \ par2repair:archivers/par2cmdline \ unrar:archivers/unrar USES= python shebangfix gettext USE_RC_SUBR= sabnzbd SHEBANG_FILES= SABnzbd.py tools/msgfmt.py NO_ARCH= yes SUB_FILES= pkg-message SUB_LIST= PYTHON_CMD=${PYTHON_CMD} WRKSRC= ${WRKDIR}/SABnzbd-${DISTVERSION} USERS= _sabnzbd GROUPS= _sabnzbd PORTDOCS= COPYRIGHT.txt \ INSTALL.txt \ ISSUES.txt \ README.mkd OPTIONS_DEFINE= 7ZIP SSL DOCS NOTIFY2 DBUS PYGOBJECT OPTIONS_DEFAULT= 7ZIP SSL 7ZIP_DESC= Needed for unpacking 7-Zip posts DBUS_DESC= DBUS support for system power management NOTIFY2_DESC= Notify2 support PYGOBJECT_DESC= PyGObject support for system tray icon (requires cairo) 7ZIP_RUN_DEPENDS= 7zz:archivers/7-zip DBUS_RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}dbus>=0:devel/py-dbus@${PY_FLAVOR} NOTIFY2_IMPLIES= DBUS NOTIFY2_RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}notify2>=0:devel/py-notify2@${PY_FLAVOR} PYGOBJECT_RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}gobject3>=3.10.2:devel/py-gobject3@${PY_FLAVOR} SSL_USES= pycryptography:run post-patch: @${REINPLACE_CMD} -e "s:%%DATADIR%%:'${DATADIR}':g" \ ${WRKSRC}/SABnzbd.py # Generate locale files do-build: cd ${WRKSRC} && ${PYTHON_CMD} tools/make_mo.py do-install: ${INSTALL_SCRIPT} ${WRKSRC}/SABnzbd.py ${STAGEDIR}${PREFIX}/bin @${MKDIR} ${STAGEDIR}${PYTHONPREFIX_SITELIBDIR}/sabnzbd cd ${WRKSRC}/sabnzbd && ${COPYTREE_SHARE} \* ${STAGEDIR}${PYTHONPREFIX_SITELIBDIR}/sabnzbd @${MKDIR} ${STAGEDIR}${DATADIR} .for i in email icons interfaces locale po tools @${MKDIR} ${STAGEDIR}${DATADIR}/${i} cd ${WRKSRC}/${i} && ${COPYTREE_SHARE} \* ${STAGEDIR}${DATADIR}/${i} .endfor post-install-DOCS-on: @${MKDIR} ${STAGEDIR}${DOCSDIR} .for i in ${PORTDOCS} ${INSTALL_DATA} ${WRKSRC}/${i} ${STAGEDIR}${DOCSDIR} .endfor .include diff --git a/news/sabnzbd/files/patch-sabctools b/news/sabnzbd/files/patch-sabctools index a9d0ee784c29..da0463501ac0 100644 --- a/news/sabnzbd/files/patch-sabctools +++ b/news/sabnzbd/files/patch-sabctools @@ -1,115 +1,116 @@ Obtained from: https://github.com/sabnzbd/sabnzbd/commit/a179f2a895259e49f3679405ad59cac06e0bf2d9 + https://github.com/sabnzbd/sabnzbd/commit/a951361fa639235e9252cd32c5c7264ff0f1a70a --- requirements.txt.orig 2023-06-07 19:24:42 UTC +++ requirements.txt @@ -1,6 +1,6 @@ # Main requirements # Note that not all sub-dependencies are listed, but only ones we know could cause trouble -sabctools==7.0.2 -+sabctools==7.1.0 ++sabctools==7.1.1 cheetah3==3.2.6.post1 cffi==1.15.1 pycparser==2.21 --- sabnzbd/assembler.py.orig 2023-06-07 19:24:42 UTC +++ sabnzbd/assembler.py @@ -27,6 +27,7 @@ from threading import Thread import ctypes from typing import Tuple, Optional, List +import sabctools import sabnzbd from sabnzbd.misc import get_all_passwords, match_str from sabnzbd.filesystem import ( @@ -160,13 +161,21 @@ class Assembler(Thread): @staticmethod def assemble(nzo: NzbObject, nzf: NzbFile, file_done: bool): - """Assemble a NZF from its table of articles - 1) Partial write: write what we have - 2) Nothing written before: write all - """ + """Assemble a NZF from its table of articles""" + # When a file exists, we cannot use "w+b" + if os.path.exists(nzf.filepath): + open_mode = "r+b" + file_sparse = True + else: + open_mode = "w+b" + file_sparse = False + # We write large article-sized chunks, so we can safely skip the buffering of Python - with open(nzf.filepath, "ab", buffering=0) as fout: + with open(nzf.filepath, open_mode, buffering=0) as fout: + # Track position, so we can prevent a seek if writing continuous + file_position = 0 + for article in nzf.decodetable: # Break if deleted during writing if nzo.status is Status.DELETED: @@ -178,9 +187,25 @@ class Assembler(Thread): # Write all decoded articles if article.decoded: + # On first write try to make the file sparse + if not file_sparse and article.file_size is not None and article.file_size > 0: + file_sparse = True + try: + sabctools.sparse(fout, article.file_size) + except: + logging.debug("Failed to make %s sparse with length %d", nzf.filepath, article.file_size) + logging.debug("Traceback: ", exc_info=True) + data = sabnzbd.ArticleCache.load_article(article) # Could be empty in case nzo was deleted if data: + if article.data_begin is not None: + # Seek ahead if needed + if article.data_begin != file_position: + fout.seek(article.data_begin) + file_position = article.data_begin + len(data) + else: + fout.seek(0, os.SEEK_END) fout.write(data) nzf.update_crc32(article.crc32, len(data)) article.on_disk = True --- sabnzbd/constants.py.orig 2023-06-07 19:24:42 UTC +++ sabnzbd/constants.py @@ -49,7 +49,7 @@ RENAMES_FILE = "__renames__" ATTRIB_FILE = "SABnzbd_attrib" REPAIR_REQUEST = "repair-all.sab" -SABCTOOLS_VERSION_REQUIRED = "7.0.2" +SABCTOOLS_VERSION_REQUIRED = "7.1.0" DB_HISTORY_VERSION = 1 DB_HISTORY_NAME = "history%s.db" % DB_HISTORY_VERSION --- sabnzbd/decoder.py.orig 2023-06-07 19:24:42 UTC +++ sabnzbd/decoder.py @@ -172,7 +172,7 @@ def decode(article: Article, raw_data: bytearray): def decode_yenc(article: Article, data: bytearray) -> bytearray: # Let SABCTools do all the heavy lifting - yenc_filename, article.data_begin, article.data_size, crc_correct = sabctools.yenc_decode(data) + yenc_filename, article.file_size, article.data_begin, article.data_size, crc_correct = sabctools.yenc_decode(data) nzf = article.nzf # Assume it is yenc --- sabnzbd/nzbstuff.py.orig 2023-06-07 19:24:42 UTC +++ sabnzbd/nzbstuff.py @@ -163,6 +163,7 @@ ArticleSaver = ( "bytes", "lowest_partnum", "decoded", + "file_size", "data_begin", "data_size", "on_disk", @@ -187,6 +188,7 @@ class Article(TryList): self.fetcher_priority: int = 0 self.tries: int = 0 # Try count self.decoded: bool = False + self.file_size: Optional[int] = None self.data_begin: Optional[int] = None self.data_size: Optional[int] = None self.on_disk: bool = False