From 021ed500aae0072e29cb67c46ad6eaf3ed1d50c1 Mon Sep 17 00:00:00 2001 From: jbannon Date: Sun, 3 Apr 2022 08:06:52 +0000 Subject: [PATCH] download strategy validator --- .../base/string_formatter_validator.py | 2 - .../validators/config/preset_validator.py | 10 ++-- .../config/sources/base_source_validator.py | 30 ----------- .../sources/soundcloud_source_validator.py | 27 ---------- .../config/sources/soundcloud_validators.py | 30 +++++++++++ .../config/sources/source_validator.py | 50 +++++++++++++++++++ .../sources/youtube_source_validator.py | 15 ------ .../config/sources/youtube_validators.py | 22 ++++++++ 8 files changed, 106 insertions(+), 80 deletions(-) delete mode 100644 ytdl_subscribe/validators/config/sources/base_source_validator.py delete mode 100644 ytdl_subscribe/validators/config/sources/soundcloud_source_validator.py create mode 100644 ytdl_subscribe/validators/config/sources/soundcloud_validators.py create mode 100644 ytdl_subscribe/validators/config/sources/source_validator.py delete mode 100644 ytdl_subscribe/validators/config/sources/youtube_source_validator.py create mode 100644 ytdl_subscribe/validators/config/sources/youtube_validators.py diff --git a/ytdl_subscribe/validators/base/string_formatter_validator.py b/ytdl_subscribe/validators/base/string_formatter_validator.py index 11e3d2ce..5cf57195 100644 --- a/ytdl_subscribe/validators/base/string_formatter_validator.py +++ b/ytdl_subscribe/validators/base/string_formatter_validator.py @@ -1,10 +1,8 @@ import re from keyword import iskeyword from typing import List -from typing import Optional from ytdl_subscribe.validators.base.string_validator import StringValidator -from ytdl_subscribe.validators.exceptions import ValidationException class StringFormatterValidator(StringValidator): diff --git a/ytdl_subscribe/validators/config/preset_validator.py b/ytdl_subscribe/validators/config/preset_validator.py index a54e1c99..8ecd3f56 100644 --- a/ytdl_subscribe/validators/config/preset_validator.py +++ b/ytdl_subscribe/validators/config/preset_validator.py @@ -3,13 +3,11 @@ from typing import Optional from ytdl_subscribe.utils.enums import SubscriptionSourceName from ytdl_subscribe.validators.base.dict_validator import DictValidator -from ytdl_subscribe.validators.config.sources.base_source_validator import ( - BaseSourceValidator, -) -from ytdl_subscribe.validators.config.sources.soundcloud_source_validator import ( +from ytdl_subscribe.validators.config.sources.soundcloud_validators import ( SoundcloudSourceValidator, ) -from ytdl_subscribe.validators.config.sources.youtube_source_validator import ( +from ytdl_subscribe.validators.config.sources.source_validator import SourceValidator +from ytdl_subscribe.validators.config.sources.youtube_validators import ( YoutubeSourceValidator, ) from ytdl_subscribe.validators.exceptions import ValidationException @@ -27,7 +25,7 @@ class PresetValidator(DictValidator): def __init__(self, name: str, value: Any): super().__init__(name=name, value=value) - self.subscription_source: Optional[BaseSourceValidator] = None + self.subscription_source: Optional[SourceValidator] = None self.subscription_source_name: Optional[str] = None for object_key, object_value in self.object_items: diff --git a/ytdl_subscribe/validators/config/sources/base_source_validator.py b/ytdl_subscribe/validators/config/sources/base_source_validator.py deleted file mode 100644 index 20d8d924..00000000 --- a/ytdl_subscribe/validators/config/sources/base_source_validator.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Any -from typing import Optional -from typing import Set - -from ytdl_subscribe.validators.base.dict_validator import DictValidator -from ytdl_subscribe.validators.base.string_validator import StringValidator -from ytdl_subscribe.validators.exceptions import ValidationException - - -class BaseSourceValidator(DictValidator): - # All media sources must define a download strategy - required_fields = {"download_strategy"} - download_strategies: Set[str] = {} - - def _validate_and_get_download_strategy(self) -> str: - download_strategy = self.validate_dict_value( - dict_value_name="download_strategy", - validator=StringValidator, - ) - - if download_strategy.value not in self.download_strategies: - raise self._validation_exception( - f"download_strategy must be one of the following: {', '.join(self.download_strategies)}" - ) - - return download_strategy.value - - def __init__(self, name: str, value: Any): - super().__init__(name=name, value=value) - self.download_strategy = self._validate_and_get_download_strategy() diff --git a/ytdl_subscribe/validators/config/sources/soundcloud_source_validator.py b/ytdl_subscribe/validators/config/sources/soundcloud_source_validator.py deleted file mode 100644 index 067e6e54..00000000 --- a/ytdl_subscribe/validators/config/sources/soundcloud_source_validator.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Optional - -from ytdl_subscribe.validators.base.bool_validator import BoolValidator -from ytdl_subscribe.validators.base.string_validator import StringValidator -from ytdl_subscribe.validators.config.sources.base_source_validator import ( - BaseSourceValidator, -) - - -class SoundcloudSourceValidator(BaseSourceValidator): - optional_fields = {"username", "skip_premiere_tracks"} - download_strategies = {"albums_and_singles"} - - def __validate_and_set_download_strategy_fields(self): - if self.download_strategy == "albums_and_singles": - self.username = self.validate_dict_value( - dict_value_name="username", - validator=StringValidator, - ).value - - def __init__(self, name: str, value: dict): - super().__init__(name=name, value=value) - self.skip_premiere_tracks = self.validate_dict_value( - "skip_premiere_tracks", BoolValidator, default=True - ).value - self.username: Optional[str] = None - self.__validate_and_set_download_strategy_fields() diff --git a/ytdl_subscribe/validators/config/sources/soundcloud_validators.py b/ytdl_subscribe/validators/config/sources/soundcloud_validators.py new file mode 100644 index 00000000..e9f5c0a0 --- /dev/null +++ b/ytdl_subscribe/validators/config/sources/soundcloud_validators.py @@ -0,0 +1,30 @@ +from ytdl_subscribe.validators.base.bool_validator import BoolValidator +from ytdl_subscribe.validators.base.string_validator import StringValidator +from ytdl_subscribe.validators.config.sources.source_validator import ( + DownloadStrategyValidator, +) +from ytdl_subscribe.validators.config.sources.source_validator import SourceValidator + + +class SoundcloudAlbumsAndSinglesDownloadValidator(DownloadStrategyValidator): + required_fields = {"username"} + + def __init__(self, name, value): + super().__init__(name, value) + self.username = self.validate_dict_value( + dict_value_name="username", validator=StringValidator + ).value + + +class SoundcloudSourceValidator(SourceValidator): + optional_fields = {"skip_premiere_tracks"} + + download_strategy_validator_mapping = { + "albums_and_singles": SoundcloudAlbumsAndSinglesDownloadValidator + } + + def __init__(self, name: str, value: dict): + super().__init__(name=name, value=value) + self.skip_premiere_tracks = self.validate_dict_value( + "skip_premiere_tracks", BoolValidator, default=True + ).value diff --git a/ytdl_subscribe/validators/config/sources/source_validator.py b/ytdl_subscribe/validators/config/sources/source_validator.py new file mode 100644 index 00000000..2d183ee5 --- /dev/null +++ b/ytdl_subscribe/validators/config/sources/source_validator.py @@ -0,0 +1,50 @@ +import copy +from typing import Any +from typing import Dict +from typing import Type + +from ytdl_subscribe.validators.base.dict_validator import DictValidator +from ytdl_subscribe.validators.base.string_validator import StringValidator + + +class DownloadStrategyValidator(DictValidator): + pass + + +class SourceValidator(DictValidator): + # All media sources must define a download strategy + required_fields = {"download_strategy"} + + # We allow extra fields at this level, once the download strategy is chosen, + # all fields in the dict should be required. + allow_extra_fields = True + + download_strategy_validator_mapping: Dict[str, Type[DownloadStrategyValidator]] = {} + + def __init__(self, name: str, value: Any): + super().__init__(name=name, value=value) + self.download_strategy_name = self.validate_dict_value( + dict_value_name="download_strategy", + validator=StringValidator, + ).value + + if self.download_strategy_name not in self.possible_download_strategies: + raise self._validation_exception( + f"download_strategy must be one of the following: {', '.join(self.possible_download_strategies)}" + ) + + # Remove all non-download strategy keys before passing the dict to the validator + download_strategy_dict = copy.deepcopy(self.dict) + for key_to_delete in self.allowed_fields: + del download_strategy_dict[key_to_delete] + + download_strategy_class = self.download_strategy_validator_mapping[ + self.download_strategy_name + ] + self.download_strategy = download_strategy_class( + name=self.name, value=download_strategy_dict + ) + + @property + def possible_download_strategies(self): + return sorted(list(self.download_strategy_validator_mapping.keys())) diff --git a/ytdl_subscribe/validators/config/sources/youtube_source_validator.py b/ytdl_subscribe/validators/config/sources/youtube_source_validator.py deleted file mode 100644 index 6420d76c..00000000 --- a/ytdl_subscribe/validators/config/sources/youtube_source_validator.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Any - -from ytdl_subscribe.validators.base.string_validator import StringValidator -from ytdl_subscribe.validators.config.sources.base_source_validator import ( - BaseSourceValidator, -) - - -class YoutubeSourceValidator(BaseSourceValidator): - optional_fields = {"playlist_id"} - download_strategies = {"playlist"} - - def __init__(self, name: str, value: Any): - super().__init__(name=name, value=value) - self.playlist_id = self.validate_dict_value("playlist_id", StringValidator) diff --git a/ytdl_subscribe/validators/config/sources/youtube_validators.py b/ytdl_subscribe/validators/config/sources/youtube_validators.py new file mode 100644 index 00000000..0f92cdae --- /dev/null +++ b/ytdl_subscribe/validators/config/sources/youtube_validators.py @@ -0,0 +1,22 @@ +from typing import Any + +from ytdl_subscribe.validators.base.string_validator import StringValidator +from ytdl_subscribe.validators.config.sources.source_validator import ( + DownloadStrategyValidator, +) +from ytdl_subscribe.validators.config.sources.source_validator import SourceValidator + + +class YoutubePlaylistDownloadValidator(DownloadStrategyValidator): + required_fields = {"playlist_id"} + + def __init__(self, name, value): + super().__init__(name, value) + self.playlist_id = self.validate_dict_value("playlist_id", StringValidator) + + +class YoutubeSourceValidator(SourceValidator): + download_strategy_validator_mapping = {"playlist": YoutubePlaylistDownloadValidator} + + def __init__(self, name: str, value: Any): + super().__init__(name=name, value=value)