mirror of
https://github.com/calibrain/shelfmark.git
synced 2026-11-10 12:38:32 +00:00
Six places read the Supported Book Formats and Supported Audiobook Formats settings on their own: post-processing, the post-process scan, IRC, slskd, Prowlarr and direct download. For ebooks they already agreed, since they all fall back to `DEFAULT_EBOOK_FORMATS`. For audiobooks they did not. The settings registry and slskd fall back to every audio format plus zip and rar, while post-processing and IRC fell back to m4b and mp3 only. They now share `shelfmark/core/formats.py`, with `get_supported_formats`, `get_supported_audiobook_formats` and a content-type aware `get_supported_formats_for`, and a shared `DEFAULT_AUDIOBOOK_FORMATS` in `core/utils.py` next to the ebook one. `policy.py` re-exports the same functions, so nothing that imports them from there changes. It is not in `policy.py` itself because importing the `postprocess` package pulls in the router, which imports the release sources, so a source could not import from it without a cycle. One behaviour difference, and only in the fallback: with the audiobook setting unset, or emptied, post-processing and IRC used to accept m4b and mp3 and now accept the full default list like slskd and the settings page already did. A configured list is read exactly as before. Direct download's own helper used the raw configured list and now reads the same normalized one, which is identical for any list the settings page can save. Also public now: `parse_size` in the Prowlarr source (slskd and Newznab imported it with the underscore) and `coerce_completed_path_timeout_seconds` in the client base handler (slskd imported that too). Not changed on purpose: slskd's `_coerce_int` looks like a copy of `coerce_int` but is not. It reads `"12.0"` as 12 and `True` as 0, where `coerce_int` gives 0 and 1. And the `_parse_size` in the IRC source is a different function, string to bytes. Tests: a new set checks that post-processing, IRC and slskd all fall back to the shared defaults and that the settings default is the shared one, and the scan-archive and IRC tests now patch the shared config instead of the per-module copies. Full suite passes.
98 lines
3.6 KiB
Python
98 lines
3.6 KiB
Python
"""One default for the Supported Book Formats setting, read the same way everywhere."""
|
|
|
|
import pytest
|
|
|
|
from shelfmark.config import settings as app_settings
|
|
from shelfmark.core.formats import get_supported_formats_for
|
|
from shelfmark.core.utils import (
|
|
DEFAULT_AUDIOBOOK_FORMATS,
|
|
DEFAULT_EBOOK_FORMATS,
|
|
normalize_format_list,
|
|
)
|
|
from shelfmark.download.postprocess import policy
|
|
|
|
DEFAULT = ["epub", "mobi"]
|
|
|
|
|
|
class TestNormalizeFormatList:
|
|
def test_a_string_splits_on_commas_and_spaces_and_drops_leading_dots(self):
|
|
assert normalize_format_list("epub, .MOBI azw3", DEFAULT) == ["epub", "mobi", "azw3"]
|
|
|
|
def test_a_list_is_lowercased_and_stripped(self):
|
|
assert normalize_format_list([" EPUB ", ".mobi", "", " "], DEFAULT) == ["epub", "mobi"]
|
|
|
|
@pytest.mark.parametrize("value", ["", " , ", [], [""], (), set()])
|
|
def test_nothing_left_falls_back_to_the_default(self, value):
|
|
assert normalize_format_list(value, DEFAULT) == DEFAULT
|
|
|
|
@pytest.mark.parametrize("value", [None, 3, 1.5, {"epub": 1}, object()])
|
|
def test_a_value_of_the_wrong_kind_falls_back_to_the_default(self, value):
|
|
assert normalize_format_list(value, DEFAULT) == DEFAULT
|
|
|
|
def test_the_default_is_returned_as_a_new_list(self):
|
|
assert normalize_format_list(None, DEFAULT_EBOOK_FORMATS) == list(DEFAULT_EBOOK_FORMATS)
|
|
|
|
|
|
def test_the_registry_default_is_the_shared_default():
|
|
field = next(
|
|
f for f in app_settings.general_settings() if getattr(f, "key", "") == "SUPPORTED_FORMATS"
|
|
)
|
|
|
|
assert field.default == list(DEFAULT_EBOOK_FORMATS)
|
|
|
|
|
|
def test_post_processing_falls_back_to_the_shared_default(monkeypatch):
|
|
class _Config:
|
|
def get(self, key, default=None, user_id=None):
|
|
return default
|
|
|
|
monkeypatch.setattr("shelfmark.core.config.config", _Config())
|
|
|
|
assert policy.get_supported_formats() == list(DEFAULT_EBOOK_FORMATS)
|
|
|
|
|
|
def test_the_audiobook_registry_default_is_the_shared_default():
|
|
field = next(
|
|
f
|
|
for f in app_settings.general_settings()
|
|
if getattr(f, "key", "") == "SUPPORTED_AUDIOBOOK_FORMATS"
|
|
)
|
|
|
|
assert field.default == list(DEFAULT_AUDIOBOOK_FORMATS)
|
|
|
|
|
|
class TestEveryReaderFallsBackToTheSameDefaults:
|
|
"""Post-processing and the sources each read the formats; none may keep its own default."""
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def unset_config(self, monkeypatch):
|
|
class _Config:
|
|
def get(self, key, default=None, user_id=None):
|
|
return default
|
|
|
|
monkeypatch.setattr("shelfmark.core.config.config", _Config())
|
|
|
|
def test_post_processing(self):
|
|
assert policy.get_supported_formats() == list(DEFAULT_EBOOK_FORMATS)
|
|
assert policy.get_supported_audiobook_formats() == list(DEFAULT_AUDIOBOOK_FORMATS)
|
|
|
|
@pytest.mark.parametrize(
|
|
("content_type", "expected"),
|
|
[
|
|
(None, DEFAULT_EBOOK_FORMATS),
|
|
("book (fiction)", DEFAULT_EBOOK_FORMATS),
|
|
("audiobook", DEFAULT_AUDIOBOOK_FORMATS),
|
|
],
|
|
)
|
|
def test_the_lookup_follows_the_content_type(self, content_type, expected):
|
|
assert get_supported_formats_for(content_type) == list(expected)
|
|
|
|
def test_irc_and_slskd(self):
|
|
from shelfmark.release_sources.irc.parser import _get_supported_formats
|
|
from shelfmark.release_sources.slskd.source import get_supported_formats
|
|
|
|
assert _get_supported_formats("audiobook") == set(DEFAULT_AUDIOBOOK_FORMATS)
|
|
assert get_supported_formats("audiobook") == set(DEFAULT_AUDIOBOOK_FORMATS)
|
|
assert _get_supported_formats("ebook") == set(DEFAULT_EBOOK_FORMATS)
|
|
assert get_supported_formats("ebook") == set(DEFAULT_EBOOK_FORMATS)
|