Compare commits

...

18 Commits

Author SHA1 Message Date
Safihre
76c58953df Pin even more requirements
Closes #2056
2022-02-04 10:09:53 +01:00
thezoggy
4ddc5caa49 pin builder setuptools to deal with breakage on pyinstaller 4.8 2022-02-04 09:08:51 +01:00
Safihre
694663bd95 Update text files for 3.5.1RC1 2022-02-03 20:09:38 +01:00
Safihre
62aba5844e Add small delay between volumes in Direct Unpack to prevent UnRar error 2022-01-31 12:23:38 +01:00
Safihre
d0d60cef05 Disable buffering when writing files in assembler 2022-01-31 12:23:31 +01:00
Safihre
3d293fdcb0 RSS feeds with HTML-chars in the feed name would result in crash 2022-01-31 12:23:23 +01:00
Safihre
96e9528046 Fix dependencies in requirements.txt and configure dependabot 2022-01-30 10:52:52 +01:00
Safihre
4ea24b3203 Black formatting update 2022-01-30 09:43:31 +01:00
Safihre
e586ead024 Update text files for 3.5.0 2022-01-28 11:39:21 +01:00
Safihre
14c80bf1dc Reduce par2cmdline output log in Debug mode 2022-01-28 11:35:59 +01:00
Safihre
bdd56e794a Prevent extra error when no 7zip is available
Closes #2036, #2035
2022-01-23 13:41:26 +01:00
Safihre
a544548934 Set Python for macOS release to 3.10.2 2022-01-21 16:53:29 +01:00
Safihre
e06c1d61fb Update text files for 3.5.0RC4 2022-01-18 09:41:26 +01:00
Safihre
600c5209c6 HTML-sanitizer would sanitize the source data
Closes #2026
2022-01-17 14:08:08 +01:00
Safihre
bee90366ee Update text files for 3.5.0RC3 2022-01-16 19:02:50 +01:00
Safihre
e9bc4e9417 Sort sevenset so x.7z.001 is always the first file 2022-01-15 17:09:21 +01:00
Safihre
f01ff15761 Failed 7zip unpack was not reported in the history 2022-01-15 17:05:03 +01:00
Safihre
356ada159d Update text files for 3.5.0RC2 2022-01-13 14:48:30 +01:00
21 changed files with 144 additions and 85 deletions

14
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "pip"
directory: "/builder"
schedule:
interval: "weekly"
- package-ecosystem: "pip"
directory: "/builder/osx"
schedule:
interval: "weekly"

View File

@@ -73,7 +73,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.10.1"
PYTHON_VERSION: "3.10.2"
MACOSX_DEPLOYMENT_TARGET: "10.9"
# We need to force compile for universal2 support
CFLAGS: -arch arm64 -arch x86_64
@@ -108,8 +108,8 @@ jobs:
pip3 install --upgrade -r requirements.txt --no-binary sabyenc3
pip3 uninstall cryptography -y
pip3 download cryptography --platform macosx_10_10_universal2 --only-binary :all: --no-deps --dest .
pip3 install cryptography --no-cache-dir --no-index --find-links .
pip3 download -r builder/osx/requirements.txt --platform macosx_10_10_universal2 --only-binary :all: --no-deps --dest .
pip3 install -r builder/osx/requirements.txt --no-cache-dir --no-index --find-links .
PYINSTALLER_COMPILE_BOOTLOADER=1 pip3 install --upgrade -r builder/requirements.txt --no-binary pyinstaller
- name: Import macOS codesign certificates

View File

@@ -1,7 +1,7 @@
Metadata-Version: 1.0
Name: SABnzbd
Version: 3.5.0RC1
Summary: SABnzbd-3.5.0RC1
Version: 3.5.1RC1
Summary: SABnzbd-3.5.1RC1
Home-page: https://sabnzbd.org
Author: The SABnzbd Team
Author-email: team@sabnzbd.org

View File

@@ -1,6 +1,11 @@
Release Notes - SABnzbd 3.5.0 Release Candidate 1
Release Notes - SABnzbd 3.5.1 Release Candidate 1
=========================================================
## Changes and bugfixes since 3.5.0
- Small changes in file assembly and Direct Unpack processing.
- RSS feeds with HTML-characters in the name resulted in crashes.
- macOS: failed to start on older macOS versions.
## Changes since 3.4.2
- Removed Python 3.6 support.
- SOCKS5 proxy support for all outgoing connections.
@@ -8,31 +13,33 @@ Release Notes - SABnzbd 3.5.0 Release Candidate 1
- `Required` server option: in case of connection failures, the queue
will be paused for a few minutes instead of skipping the server.
- Added Special option to preserve paused state after a restart.
- Show an estimated time-left indicator for repair and unpacking.
- Show an estimated time-left indicator for repair and unpacking.
- Require TLS version 1.2 or higher for SSL news server connections.
- Setting custom ciphers forces the maximum TLS version to 1.2.
- Print low-level Windows status error on `IOError`.
- Reduced memory usage during and after parsing `.nzb` files.
- Handle multiple passwords stored in NZB-file.
- macOS/Linux: `Permissions` are only applied if any are set.
- macOS/Windows: updated to Python 3.10.1.
- macOS: run native on M1 systems. However, included tools
- macOS/Windows: updated to Python 3.10.2.
- macOS: run native on M1 systems. However, included tools
(`par2`, `unrar` and `7za`) still require Rosetta emulation.
- Snap: updated to `core20` base and restore 7zip support.
## Bugfixes since 3.4.2
- Global interface settings would not always be applied correctly.
- Email notification setting was not shown correctly.
- Improvements and fixes for `Defobfuscate final filenames`.
- `Post-Process Only Verified Jobs` would not always work as intended.
- Correctly detect too little disk space when unpacking 7zip's.
- Improvements to handling of repair by MultiPar and par2cmdline.
- HTML characters in configuration fields were shown incorrectly.
- On Retry the number of downloaded bytes could exceed the total bytes.
- `unrar` logging of Direct Unpack was not logged if it was aborted.
- Windows: `portable.cmd` was not included in the release.
- Windows: print low-level Windows error on `IOError`.
## Upgrade notices
- The download statistics file `totals10.sab` is updated in 3.2.x
version. If you downgrade to 3.1.x or lower, detailed download
- The download statistics file `totals10.sab` is updated in 3.2.x
version. If you downgrade to 3.1.x or lower, detailed download
statistics will be lost.
## Known problems and solutions

View File

@@ -0,0 +1,3 @@
# Special requirements for macOS universal2 binary release
# This way dependabot can auto-update them
cryptography==36.0.1

View File

@@ -1,9 +1,13 @@
# Basic build requirements
pyinstaller>=4.8
setuptools
# Note that not all sub-dependencies are listed, but only ones we know could cause trouble
pyinstaller==4.8
pyinstaller-hooks-contrib==2022.0
altgraph==0.17.2
wrapt==1.13.3
setuptools==60.6.0
pkginfo
certifi
pygithub
# For the OSX build specific
dmgbuild; sys_platform == 'darwin'
dmgbuild==1.5.2; sys_platform == 'darwin'

View File

@@ -53,7 +53,7 @@
</td>
<td class="title">
<a href="?feed=$rss[$feed_item]['link']" class="subscription-title path feed <!--#if int($rss[$feed_item]['enable']) != 0 then 'feed_enabled' else 'feed_disabled'#-->">
$feed_item
$feed_item_html
</a>
</td>
<td class="controls">
@@ -102,7 +102,7 @@
</div>
<!--#end if#-->
<!--#if $active_feed#-->
<!--#set $feed = $active_feed#-->
<!--#set $feed = html.unescape($active_feed)#-->
<div class="section rss-section">
<div class="padTable">
<a class="main-helplink" href="$helpuri$help_uri" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a>
@@ -113,12 +113,12 @@
<!--#if $error#-->
<div class="alert alert-danger">
<span class="glyphicon glyphicon-exclamation-sign"></span>
<!--#echo html.escape($error)#-->
$error
</div>
<!--#end if#-->
<form action="upd_rss_feed" method="post">
<input type="hidden" name="apikey" value="$apikey" />
<input type="hidden" name="feed" value="$feed" />
<input type="hidden" name="feed" value="$active_feed" />
<input type="hidden" name="uri" value="$rss[$feed]['uris']" />
<table class="catTable">
<thead>
@@ -210,7 +210,7 @@
<form action="upd_rss_filter" method="post">
<input type="hidden" name="apikey" value="$apikey" />
<input type="hidden" name="index" value="$rss[$feed]['filtercount']" />
<input type="hidden" name="feed" value="$feed" />
<input type="hidden" name="feed" value="$active_feed" />
<table class="catTable">
<tbody>
<tr>
@@ -286,7 +286,7 @@
<form action="upd_rss_filter" method="post" autocomplete="off">
<input type="hidden" name="apikey" value="$apikey" />
<input type="hidden" name="index" value="$fnum" />
<input type="hidden" name="feed" value="$feed" />
<input type="hidden" name="feed" value="$active_feed" />
<table class="catTable">
<tbody>
<tr class="<!--#if $odd then " alt " else " "#--> <!--#if $filter[3]!="A" and $filter[3]!="S" then 'disabled_options_rule' else ""#-->">
@@ -363,13 +363,13 @@
<!--#end for#-->
<form action="download_rss_feed" method="post">
<input type="hidden" name="apikey" value="$apikey" />
<input type="hidden" name="feed" value="$feed" />
<input type="hidden" name="feed" value="$active_feed" />
<div class="padding">
<button type="button" class="btn btn-default testFeed" rel="$feed"><span class="glyphicon glyphicon-sort"></span> $T('button-preFeed')</button>
<button type="button" class="btn btn-default testFeed" rel="$active_feed"><span class="glyphicon glyphicon-sort"></span> $T('button-preFeed')</button>
<button type="submit" class="btn btn-default Save"><span class="glyphicon glyphicon-forward"></span> $T('button-forceFeed')</button>
<button type="button" class="btn btn-default cleanFeed"><span class="glyphicon glyphicon-trash"></span> $T('button-clear') $T('rss-done')</button>
<!--#if $evalButton#-->
<button type="button" class="btn btn-default evalFeed" rel="$feed"><span class="glyphicon glyphicon-ok-circle"></span> $T('button-evalFeed')</button>
<button type="button" class="btn btn-default evalFeed" rel="$active_feed"><span class="glyphicon glyphicon-ok-circle"></span> $T('button-evalFeed')</button>
<!--#end if#-->
</div>
</form>
@@ -402,7 +402,7 @@
<tr class="infoTableSeperator">
<td>
<form action="download" method="get">
<input type="hidden" value="$feed" name="feed" />
<input type="hidden" value="$active_feed" name="feed" />
<input type="hidden" name="apikey" value="$apikey" />
<input type="hidden" name="url" value="$job['url']" />
<input type="hidden" name="nzbname" value="$job['nzbname']" />
@@ -446,7 +446,7 @@
<tr class="infoTableSeperator">
<td>
<form action="download" method="get">
<input type="hidden" value="$feed" name="feed" />
<input type="hidden" value="$active_feed" name="feed" />
<input type="hidden" name="apikey" value="$apikey" />
<input type="hidden" name="url" value="$job['url']" />
<input type="hidden" name="nzbname" value="$job['nzbname']" />
@@ -475,7 +475,7 @@
<div class="tab-pane padTable" id="rss-tab-done">
<!--#if $downloaded#-->
<form action="clean_rss_jobs" method="post">
<input type="hidden" value="$feed" name="feed" />
<input type="hidden" value="$active_feed" name="feed" />
<input type="hidden" name="apikey" value="$apikey" />
<table class="catTable">
<thead>

View File

@@ -1,22 +1,36 @@
sabyenc3>=4.0.0
cheetah3>=3.0.0
cryptography
feedparser>=6.0.0
configobj
cheroot
cherrypy
portend
chardet
notify2
PySocks
puremagic
guessit>=3.1.0
# Main requirements
# Note that not all sub-dependencies are listed, but only ones we know could cause trouble
sabyenc3==4.0.2
cheetah3==3.2.6
cryptography==36.0.1
cffi==1.15
pycparser==2.21
feedparser==6.0.8
configobj==5.0.6
cheroot==8.6.0
cherrypy==18.6.1
jaraco.functools==3.5.0
jaraco.collections==3.5.1
jaraco.text==3.7.0
jaraco.classes==3.2.1
jaraco.context==4.1.1
more-itertools==8.12.0
tempora==5.0.1
portend==3.1.0
chardet==4.0.0
PySocks==1.7.1
puremagic==1.11
guessit==3.4.3
rebulk==3.1.0
# Windows system integration
pywin32>=227; sys_platform == 'win32'
pywin32==303; sys_platform == 'win32'
# macOS system calls
pyobjc; sys_platform == 'darwin'
pyobjc==8.1; sys_platform == 'darwin'
# Linux notifications
notify2==0.3.1; sys_platform != 'win32' and sys_platform != 'darwin'
# Optional support for *nix tray icon.
# Note that pygobject depends on pycairo, which requires pkg-config and cairo headers.

View File

@@ -119,7 +119,7 @@ class Assembler(Thread):
# Log traceback
logging.info("Traceback: ", exc_info=True)
if sabnzbd.WIN32:
logging.info("Winerror: %s", hex(ctypes.windll.ntdll.RtlGetLastNtStatus() + 2 ** 32))
logging.info("Winerror: %s", hex(ctypes.windll.ntdll.RtlGetLastNtStatus() + 2**32))
# Pause without saving
sabnzbd.Downloader.pause()
continue
@@ -214,7 +214,8 @@ class Assembler(Thread):
if not nzf.md5:
nzf.md5 = hashlib.md5()
with open(nzf.filepath, "ab") as fout:
# We write large article-sized chunks, so we can safely skip the buffering of Python
with open(nzf.filepath, "ab", buffering=0) as fout:
for article in nzf.decodetable:
# Break if deleted during writing
if nzf.nzo.status is Status.DELETED:

View File

@@ -401,7 +401,7 @@ class ConfigServer:
self.displayname = OptionStr(name, "displayname", add=False)
self.host = OptionStr(name, "host", add=False)
self.port = OptionNumber(name, "port", 119, 0, 2 ** 16 - 1, add=False)
self.port = OptionNumber(name, "port", 119, 0, 2**16 - 1, add=False)
self.timeout = OptionNumber(name, "timeout", 60, 20, 240, add=False)
self.username = OptionStr(name, "username", add=False)
self.password = OptionPassword(name, "password", add=False)

View File

@@ -41,9 +41,9 @@ ANFO = namedtuple("ANFO", "article_sum cache_size cache_limit")
DEF_FOLDER_MAX = 256 - 10
DEF_FILE_MAX = 255 - 10 # max filename length on modern filesystems, minus some room for extra chars later on
GIGI = float(2 ** 30)
MEBI = float(2 ** 20)
KIBI = float(2 ** 10)
GIGI = float(2**30)
MEBI = float(2**20)
KIBI = float(2**10)
BYTES_FILE_NAME_OLD = "totals9.sab"
BYTES_FILE_NAME = "totals10.sab"

View File

@@ -54,20 +54,20 @@ class DirectUnpacker(threading.Thread):
self.nzo: NzbObject = nzo
self.active_instance: Optional[subprocess.Popen] = None
self.killed = False
self.killed: bool = False
self.next_file_lock = threading.Condition(threading.RLock())
self.unpack_dir_info = None
self.rarfile_nzf: Optional[NzbFile] = None
self.cur_setname = None
self.cur_volume = 0
self.total_volumes = {}
self.unpack_time = 0.0
self.cur_setname: Optional[str] = None
self.cur_volume: int = 0
self.total_volumes: Dict[str, int] = {}
self.unpack_time: float = 0.0
self.success_sets: Dict[str, Tuple[List[str], List[str]]] = {}
self.next_sets = []
self.next_sets: List[NzbFile] = []
self.duplicate_lines = 0
self.duplicate_lines: int = 0
nzo.direct_unpacker = self
@@ -292,9 +292,13 @@ class DirectUnpacker(threading.Thread):
# Possible that the instance was deleted while locked
if not self.killed:
# Sometimes the assembler is still working on the file, resulting in "Unexpected end of archive".
# So we delay a tiny bit before we continue. This is not the cleanest solution, but it works.
time.sleep(0.1)
# If unrar stopped or is killed somehow, writing will cause a crash
try:
# Give unrar some time to do it's thing
# Give unrar some time to do its thing
self.active_instance.stdin.write(b"C\n")
start_time = time.time()
time.sleep(0.1)
@@ -389,7 +393,7 @@ class DirectUnpacker(threading.Thread):
# The first NZF
self.rarfile_nzf = self.have_next_volume()
# Ignore if maybe this set is not there any more
# Ignore if maybe this set is not there anymore
# This can happen due to race/timing issues when creating the sets
if not self.rarfile_nzf:
return

View File

@@ -890,7 +890,7 @@ def renamer(old: str, new: str, create_local_directories: bool = False) -> str:
time.sleep(2)
else:
raise
raise OSError("Failed to rename (Winerr %s)" % hex(ctypes.windll.ntdll.RtlGetLastNtStatus() + 2 ** 32))
raise OSError("Failed to rename (Winerr %s)" % hex(ctypes.windll.ntdll.RtlGetLastNtStatus() + 2**32))
else:
shutil.move(old, new)
return new

View File

@@ -30,6 +30,7 @@ import hashlib
import socket
import ssl
import functools
import copy
from random import randint
from xml.sax.saxutils import escape
from Cheetah.Template import Template
@@ -367,8 +368,11 @@ def check_apikey(kwargs):
def template_filtered_response(file: str, search_list: Dict[str, Any]):
"""Wrapper for Cheetah response"""
recursive_html_escape(search_list, exclude_items=("webdir",))
return Template(file=file, searchList=[search_list], compilerSettings=CHEETAH_DIRECTIVES).respond()
# We need a copy, because otherwise source-dicts might be modified
search_list_copy = copy.deepcopy(search_list)
# 'filters' is excluded because the RSS-filters are listed twice
recursive_html_escape(search_list_copy, exclude_items=("webdir", "filters"))
return Template(file=file, searchList=[search_list_copy], compilerSettings=CHEETAH_DIRECTIVES).respond()
def log_warning_and_ip(txt):
@@ -1445,7 +1449,7 @@ class ConfigRss:
if filt:
feed_cfg.filters.update(
int(kwargs.get("index", 0)), (cat, pp, script, kwargs.get("filter_type"), filt, prio, enabled)
int(kwargs.get("index", 0)), [cat, pp, script, kwargs.get("filter_type"), filt, prio, enabled]
)
# Move filter if requested

View File

@@ -733,7 +733,7 @@ def loadavg():
return p
def format_time_string(seconds):
def format_time_string(seconds: float) -> str:
"""Return a formatted and translated time string"""
def unit(single, n):
@@ -1080,11 +1080,13 @@ def recursive_html_escape(input_dict_or_list: Union[Dict[str, Any], List], exclu
iterator = enumerate(input_dict_or_list)
for key, value in iterator:
# We ignore any other than str and those on the exclude_items-list
if isinstance(value, str) and key not in exclude_items:
input_dict_or_list[key] = html.escape(value, quote=True)
if isinstance(value, (dict, list)):
recursive_html_escape(value)
# Ignore any keys that are not safe to convert
if key not in exclude_items:
# We ignore any other than str
if isinstance(value, str):
input_dict_or_list[key] = html.escape(value, quote=True)
if isinstance(value, (dict, list)):
recursive_html_escape(value, exclude_items=exclude_items)
else:
raise ValueError("Expected dict or str, got %s" % type(input_dict_or_list))

View File

@@ -970,6 +970,8 @@ def unseven(nzo: NzbObject, workdir_complete: str, one_folder: bool, sevens: Lis
logging.info("Starting extract on 7zip set/file: %s ", seven_set)
nzo.set_action_line(T("Unpacking"), setname_from_path(seven_set))
# Sort, so that x.001 is the first one
seven_sets[seven_set].sort()
seven_path = seven_sets[seven_set][0]
if workdir_complete and seven_path.startswith(nzo.download_path):
@@ -978,7 +980,9 @@ def unseven(nzo: NzbObject, workdir_complete: str, one_folder: bool, sevens: Lis
extraction_path = os.path.split(seven_path)[0]
res, new_files_set = seven_extract(nzo, seven_path, seven_set, extraction_path, one_folder)
if not res and nzo.delete:
if res:
unseven_failed = True
elif nzo.delete:
for seven in seven_sets[seven_set]:
try:
remove_file(seven)
@@ -1284,7 +1288,7 @@ def par2cmdline_verify(
if line == "":
continue
if not line.startswith(("Repairing:", "Scanning:", "Loading:")):
if not line.startswith(("Repairing:", "Scanning:", "Loading:", "Solving:", "Constructing:")):
lines.append(line)
if line.startswith(("Invalid option specified", "Invalid thread option", "Cannot specify recovery file count")):
@@ -2046,12 +2050,14 @@ def unrar_check(rar: str) -> Tuple[int, bool]:
def sevenzip_check(sevenzip: str) -> str:
"""Return version of 7zip, currently as a string"""
try:
seven_command_output = run_command([sevenzip])
# Example: 7-Zip (z) 21.06 (x64) : Copyright (c) 1999-2021 Igor Pavlov : 2021-11-24
return re.search(r"(\d+\.\d+).*Copyright", seven_command_output).group(1)
except:
return ""
if sevenzip:
try:
seven_command_output = run_command([sevenzip])
# Example: 7-Zip (z) 21.06 (x64) : Copyright (c) 1999-2021 Igor Pavlov : 2021-11-24
return re.search(r"(\d+\.\d+).*Copyright", seven_command_output).group(1)
except:
pass
return ""
def par2_mt_check(par2_path: str) -> bool:

View File

@@ -435,7 +435,7 @@ def nzbfile_parser(full_nzb_path: str, nzo):
nzo.increase_bad_articles_counter("duplicate_articles")
else:
logging.info("Skipping duplicate article (%s)", article_id)
elif segment_size <= 0 or segment_size >= 2 ** 23:
elif segment_size <= 0 or segment_size >= 2**23:
# Perform sanity check (not negative, 0 or larger than 8MB) on article size
# We use this value later to allocate memory in cache and sabyenc
logging.info("Skipping article %s due to strange size (%s)", article_id, segment_size)

View File

@@ -34,7 +34,7 @@ def measure_speed_from_url(url: str) -> float:
logging.debug("Downloaded bytes: %d", downloaded_bytes)
logging.debug("Duration in seconds: %f", duration)
return downloaded_bytes / 1024 ** 2 / duration
return downloaded_bytes / 1024**2 / duration
def bytes_to_bits(megabytes_per_second: float) -> float:

View File

@@ -264,7 +264,7 @@ class TestOtherApi(ApiTestFunctions):
if round(limit_pct / 100 * linespeed_value) > 20:
speed_abs = str(round(limit_pct / 100 * linespeed_value)) + "M"
else:
speed_abs = str(round(limit_pct * 2 ** 10 * linespeed_value / 100)) + "K"
speed_abs = str(round(limit_pct * 2**10 * linespeed_value / 100)) + "K"
else:
speed_abs = str(round(limit_pct / 100 * from_units(linespeed)))
assert self._get_api_json("config", extra_args={"name": "speedlimit", "value": speed_abs})["status"] is True
@@ -615,7 +615,7 @@ class TestQueueApi(ApiTestFunctions):
def size_in_bytes(size):
# Helper function for list.sort() to deal with B/KB/MB in size values
if size.endswith(" MB"):
return float(size.strip(" MB")) * 1024 ** 2
return float(size.strip(" MB")) * 1024**2
if size.endswith(" KB"):
return float(size.strip(" KB")) * 1024
if size.endswith(" B"):

View File

@@ -124,12 +124,12 @@ class TestMisc:
assert "10.0 M" == misc.to_units(1024 * 1024 * 10)
assert "100.0 M" == misc.to_units(1024 * 1024 * 100)
assert "9.8 G" == misc.to_units(1024 * 1024 * 10000)
assert "1024.0 P" == misc.to_units(1024 ** 6)
assert "1024.0 P" == misc.to_units(1024**6)
def test_unit_back_and_forth(self):
assert 100 == misc.from_units(misc.to_units(100))
assert 1024 == misc.from_units(misc.to_units(1024))
assert 1024 ** 3 == misc.from_units(misc.to_units(1024 ** 3))
assert 1024**3 == misc.from_units(misc.to_units(1024**3))
def test_caller_name(self):
@set_config({"log_level": 0})

View File

@@ -208,21 +208,21 @@ class FakeHistoryDB(db.HistoryDB):
nzo.status = choice([Status.COMPLETED, choice(self.status_options)])
nzo.fail_msg = "¡Fracaso absoluto!" if nzo.status == Status.FAILED else ""
nzo.nzo_id = "SABnzbd_nzo_%s" % ("".join(choice(ascii_lowercase + digits) for i in range(8)))
nzo.bytes_downloaded = randint(1024, 1024 ** 4)
nzo.bytes_downloaded = randint(1024, 1024**4)
nzo.md5sum = "".join(choice("abcdef" + digits) for i in range(32))
nzo.repair, nzo.unpack, nzo.delete = pp_to_opts(choice(list(db._PP_LOOKUP.keys()))) # for "pp"
nzo.nzo_info = {"download_time": randint(1, 10 ** 4)}
nzo.nzo_info = {"download_time": randint(1, 10**4)}
nzo.unpack_info = {"unpack_info": "placeholder unpack_info line\r\n" * 3}
nzo.futuretype = False # for "report", only True when fetching an URL
nzo.download_path = os.path.join(os.path.dirname(db.HistoryDB.db_path), "placeholder_downpath")
# Mock time when calling add_history_db() to randomize completion times
almost_time = mock.Mock(return_value=time.time() - randint(0, 10 ** 8))
almost_time = mock.Mock(return_value=time.time() - randint(0, 10**8))
with mock.patch("time.time", almost_time):
self.add_history_db(
nzo,
storage=os.path.join(os.path.dirname(db.HistoryDB.db_path), "placeholder_workdir"),
postproc_time=randint(1, 10 ** 3),
postproc_time=randint(1, 10**3),
script_output="",
script_line="",
)