download strategy validate
This commit is contained in:
parent
d3c2c14452
commit
c33f0d84ee
7 changed files with 109 additions and 13 deletions
|
|
@ -114,6 +114,11 @@ class DownloadStrategyValidator(StrictDictValidator):
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
The downloader class
|
The downloader class
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
ValidationException
|
||||||
|
If the download strategy is invalid
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return DownloadStrategyMapping.get(
|
return DownloadStrategyMapping.get(
|
||||||
|
|
@ -129,15 +134,46 @@ class Preset(StrictDictValidator):
|
||||||
# and ensure required keys are present.
|
# and ensure required keys are present.
|
||||||
_optional_keys = PRESET_KEYS
|
_optional_keys = PRESET_KEYS
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _validate_download_strategy(cls, name: str, value: Dict) -> None:
|
||||||
|
sources: List[str] = []
|
||||||
|
for source_name in DownloadStrategyMapping.sources():
|
||||||
|
if source_name in value:
|
||||||
|
sources.append(source_name)
|
||||||
|
|
||||||
|
if len(sources) > 1:
|
||||||
|
raise validation_exception(
|
||||||
|
name=name,
|
||||||
|
error_message=f"Contains the sources {', '.join(sources)} but can only have one",
|
||||||
|
)
|
||||||
|
|
||||||
|
# If no sources, nothing more to validate
|
||||||
|
if not sources:
|
||||||
|
return
|
||||||
|
|
||||||
|
source_name = sources[0]
|
||||||
|
source_dict = copy.deepcopy(value[source_name])
|
||||||
|
|
||||||
|
downloader = DownloadStrategyValidator(name=f"{name}.{source_name}", value=source_dict).get(
|
||||||
|
downloader_source=source_name
|
||||||
|
)
|
||||||
|
del source_dict["download_strategy"]
|
||||||
|
|
||||||
|
downloader.downloader_options_type.partial_validate(
|
||||||
|
name=f"{name}.{source_name}", value=source_dict
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def preset_partial_validate(cls, config: ConfigValidator, name: str, value: Any) -> None:
|
def preset_partial_validate(cls, config: ConfigValidator, name: str, value: Any) -> None:
|
||||||
# Ensure value is a dict
|
# Ensure value is a dict
|
||||||
_ = DictValidator(name=name, value=value)
|
_ = DictValidator(name=name, value=value)
|
||||||
assert isinstance(value, dict)
|
assert isinstance(value, dict)
|
||||||
|
|
||||||
|
cls._validate_download_strategy(name, value)
|
||||||
cls._partial_validate_key(name, value, "output_options", OutputOptions)
|
cls._partial_validate_key(name, value, "output_options", OutputOptions)
|
||||||
cls._partial_validate_key(name, value, "ytdl_options", YTDLOptions)
|
cls._partial_validate_key(name, value, "ytdl_options", YTDLOptions)
|
||||||
cls._partial_validate_key(name, value, "overrides", Overrides)
|
cls._partial_validate_key(name, value, "overrides", Overrides)
|
||||||
|
|
||||||
for plugin_name in PluginMapping.plugins():
|
for plugin_name in PluginMapping.plugins():
|
||||||
cls._partial_validate_key(
|
cls._partial_validate_key(
|
||||||
name,
|
name,
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,12 @@ class CollectionValidator(StrictDictValidator, AddsVariablesMixin):
|
||||||
|
|
||||||
_required_keys = {"urls"}
|
_required_keys = {"urls"}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def partial_validate(cls, name: str, value: Any) -> None:
|
||||||
|
if isinstance(value, dict):
|
||||||
|
value["urls"] = value.get("urls", [{"url": "placeholder"}])
|
||||||
|
_ = cls(name, value)
|
||||||
|
|
||||||
def __init__(self, name, value):
|
def __init__(self, name, value):
|
||||||
super().__init__(name, value)
|
super().__init__(name, value)
|
||||||
self._urls = self._validate_key(key="urls", validator=CollectionUrlListValidator)
|
self._urls = self._validate_key(key="urls", validator=CollectionUrlListValidator)
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,13 @@ class SharedNfoTagsOptions(PluginOptions):
|
||||||
def __init__(self, name, value):
|
def __init__(self, name, value):
|
||||||
super().__init__(name, value)
|
super().__init__(name, value)
|
||||||
|
|
||||||
self._nfo_name = self._validate_key(key="nfo_name", validator=StringFormatterValidator)
|
self._nfo_name = self._validate_key_if_present(
|
||||||
self._nfo_root = self._validate_key(key="nfo_root", validator=StringFormatterValidator)
|
key="nfo_name", validator=StringFormatterValidator
|
||||||
self._tags = self._validate_key(key="tags", validator=NfoTagsValidator)
|
)
|
||||||
|
self._nfo_root = self._validate_key_if_present(
|
||||||
|
key="nfo_root", validator=StringFormatterValidator
|
||||||
|
)
|
||||||
|
self._tags = self._validate_key_if_present(key="tags", validator=NfoTagsValidator)
|
||||||
self._kodi_safe = self._validate_key_if_present(
|
self._kodi_safe = self._validate_key_if_present(
|
||||||
key="kodi_safe", validator=BoolValidator, default=False
|
key="kodi_safe", validator=BoolValidator, default=False
|
||||||
).value
|
).value
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
presets:
|
|
||||||
|
|
||||||
kodi-music-videos:
|
|
||||||
preset:
|
|
||||||
- "jellyfin-music-videos"
|
|
||||||
- "kodi-safe"
|
|
||||||
|
|
@ -3,7 +3,7 @@ presets:
|
||||||
kodi_music_video:
|
kodi_music_video:
|
||||||
generic:
|
generic:
|
||||||
download_strategy: "source"
|
download_strategy: "source"
|
||||||
music_video_url: "{music_video_url}"
|
url: "{music_video_url}"
|
||||||
|
|
||||||
output_options:
|
output_options:
|
||||||
output_directory: "{music_video_directory}"
|
output_directory: "{music_video_directory}"
|
||||||
|
|
@ -18,6 +18,7 @@ presets:
|
||||||
|
|
||||||
collection_season_1:
|
collection_season_1:
|
||||||
generic:
|
generic:
|
||||||
|
download_strategy: "collection"
|
||||||
urls:
|
urls:
|
||||||
- url: "{collection_season_1_url}"
|
- url: "{collection_season_1_url}"
|
||||||
variables:
|
variables:
|
||||||
|
|
@ -42,6 +43,7 @@ presets:
|
||||||
|
|
||||||
collection_season_2:
|
collection_season_2:
|
||||||
generic:
|
generic:
|
||||||
|
download_strategy: "collection"
|
||||||
urls:
|
urls:
|
||||||
- url: "{collection_season_2_url}"
|
- url: "{collection_season_2_url}"
|
||||||
variables:
|
variables:
|
||||||
|
|
@ -60,6 +62,7 @@ presets:
|
||||||
|
|
||||||
collection_season_3:
|
collection_season_3:
|
||||||
generic:
|
generic:
|
||||||
|
download_strategy: "collection"
|
||||||
urls:
|
urls:
|
||||||
- url: "{collection_season_3_url}"
|
- url: "{collection_season_3_url}"
|
||||||
variables:
|
variables:
|
||||||
|
|
@ -78,6 +81,7 @@ presets:
|
||||||
|
|
||||||
collection_season_4:
|
collection_season_4:
|
||||||
generic:
|
generic:
|
||||||
|
download_strategy: "collection"
|
||||||
urls:
|
urls:
|
||||||
- url: "{collection_season_4_url}"
|
- url: "{collection_season_4_url}"
|
||||||
variables:
|
variables:
|
||||||
|
|
@ -96,6 +100,7 @@ presets:
|
||||||
|
|
||||||
collection_season_5:
|
collection_season_5:
|
||||||
generic:
|
generic:
|
||||||
|
download_strategy: "collection"
|
||||||
urls:
|
urls:
|
||||||
- url: "{collection_season_5_url}"
|
- url: "{collection_season_5_url}"
|
||||||
variables:
|
variables:
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ from typing import Dict
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from ytdl_sub.config.config_file import ConfigFile
|
||||||
from ytdl_sub.config.preset import Preset
|
from ytdl_sub.config.preset import Preset
|
||||||
from ytdl_sub.plugins.nfo_tags import NfoTagsOptions
|
from ytdl_sub.plugins.nfo_tags import NfoTagsOptions
|
||||||
from ytdl_sub.utils.exceptions import StringFormattingVariableNotFoundException
|
from ytdl_sub.utils.exceptions import StringFormattingVariableNotFoundException
|
||||||
|
|
@ -203,6 +204,56 @@ class TestPreset:
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_partial_validate(self, config_file):
|
|
||||||
for preset_name, preset_dict in config_file.presets.dict.items():
|
class TestPresetPartialValidate:
|
||||||
Preset.preset_partial_validate(config_file, preset_name, preset_dict)
|
@pytest.mark.parametrize(
|
||||||
|
"preset_dict",
|
||||||
|
[
|
||||||
|
{"nfo_tags": {"tags": {"key-1": "preset_0"}}},
|
||||||
|
{"output_directory_nfo_tags": {"nfo_root": "test"}},
|
||||||
|
{"output_directory": {"file_name": "test"}},
|
||||||
|
{"output_directory": {"keep_files_after": "today"}},
|
||||||
|
{"ytdl_options": {"format": "best"}},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_partial_validate(self, preset_dict):
|
||||||
|
_ = ConfigFile(
|
||||||
|
name="test_partial_validate",
|
||||||
|
value={
|
||||||
|
"configuration": {"working_directory": "."},
|
||||||
|
"presets": {"partial_preset": preset_dict},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"preset_dict",
|
||||||
|
[
|
||||||
|
{"youtube": {}, "generic": {}}, # multiple sources
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_partial_validate__bad_sources(self, preset_dict):
|
||||||
|
with pytest.raises(ValidationException):
|
||||||
|
_ = ConfigFile(
|
||||||
|
name="test_partial_validate",
|
||||||
|
value={
|
||||||
|
"configuration": {"working_directory": "."},
|
||||||
|
"presets": {"partial_preset": preset_dict},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"preset_dict",
|
||||||
|
[
|
||||||
|
{"nfo_tags": {"tags": {"key-1": {"attributes": {"test": "2"}}}}},
|
||||||
|
{"generic": {"urls": {"variables_to_set": {"name": "value"}}}},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_partial_validate__incomplete_list_item(self, preset_dict):
|
||||||
|
with pytest.raises(ValidationException):
|
||||||
|
_ = ConfigFile(
|
||||||
|
name="test_partial_validate",
|
||||||
|
value={
|
||||||
|
"configuration": {"working_directory": "."},
|
||||||
|
"presets": {"partial_preset": preset_dict},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue