Added
Link Here
|
1 |
--- sabnzbd/assembler.py.orig 2023-06-07 19:24:42 UTC |
2 |
+++ sabnzbd/assembler.py |
3 |
@@ -27,6 +27,7 @@ from threading import Thread |
4 |
import ctypes |
5 |
from typing import Tuple, Optional, List |
6 |
|
7 |
+import sabctools |
8 |
import sabnzbd |
9 |
from sabnzbd.misc import get_all_passwords, match_str |
10 |
from sabnzbd.filesystem import ( |
11 |
@@ -160,13 +161,21 @@ class Assembler(Thread): |
12 |
|
13 |
@staticmethod |
14 |
def assemble(nzo: NzbObject, nzf: NzbFile, file_done: bool): |
15 |
- """Assemble a NZF from its table of articles |
16 |
- 1) Partial write: write what we have |
17 |
- 2) Nothing written before: write all |
18 |
- """ |
19 |
+ """Assemble a NZF from its table of articles""" |
20 |
|
21 |
+ # When a file exists, we cannot use "w+b" |
22 |
+ if os.path.exists(nzf.filepath): |
23 |
+ open_mode = "r+b" |
24 |
+ file_sparse = True |
25 |
+ else: |
26 |
+ open_mode = "w+b" |
27 |
+ file_sparse = False |
28 |
+ |
29 |
# We write large article-sized chunks, so we can safely skip the buffering of Python |
30 |
- with open(nzf.filepath, "ab", buffering=0) as fout: |
31 |
+ with open(nzf.filepath, open_mode, buffering=0) as fout: |
32 |
+ # Track position, so we can prevent a seek if writing continuous |
33 |
+ file_position = 0 |
34 |
+ |
35 |
for article in nzf.decodetable: |
36 |
# Break if deleted during writing |
37 |
if nzo.status is Status.DELETED: |
38 |
@@ -178,9 +187,25 @@ class Assembler(Thread): |
39 |
|
40 |
# Write all decoded articles |
41 |
if article.decoded: |
42 |
+ # On first write try to make the file sparse |
43 |
+ if not file_sparse and article.file_size is not None and article.file_size > 0: |
44 |
+ file_sparse = True |
45 |
+ try: |
46 |
+ sabctools.sparse(fout, article.file_size) |
47 |
+ except: |
48 |
+ logging.debug("Failed to make %s sparse with length %d", nzf.filepath, article.file_size) |
49 |
+ logging.debug("Traceback: ", exc_info=True) |
50 |
+ |
51 |
data = sabnzbd.ArticleCache.load_article(article) |
52 |
# Could be empty in case nzo was deleted |
53 |
if data: |
54 |
+ if article.data_begin is not None: |
55 |
+ # Seek ahead if needed |
56 |
+ if article.data_begin != file_position: |
57 |
+ fout.seek(article.data_begin) |
58 |
+ file_position = article.data_begin + len(data) |
59 |
+ else: |
60 |
+ fout.seek(0, os.SEEK_END) |
61 |
fout.write(data) |
62 |
nzf.update_crc32(article.crc32, len(data)) |
63 |
article.on_disk = True |