diff --git a/ytdl_subscribe/subscriptions/subscription.py b/ytdl_subscribe/subscriptions/subscription.py index ddc6fe21..f4d7e7e6 100644 --- a/ytdl_subscribe/subscriptions/subscription.py +++ b/ytdl_subscribe/subscriptions/subscription.py @@ -108,10 +108,14 @@ class Subscription(object): custom_root=nfo_options.nfo_root.value, attr_type=False, ) - nfo_file_path = entry.apply_formatter( + + nfo_file_name = entry.apply_formatter( format_string=nfo_options.nfo_name.format_string, overrides=self.overrides.dict, ) + nfo_file_path = Path(self.output_options.output_directory.value) / Path( + nfo_file_name + ) with open(nfo_file_path, "wb") as f: f.write(xml) diff --git a/ytdl_subscribe/validators/base/strict_dict_validator.py b/ytdl_subscribe/validators/base/strict_dict_validator.py index 8ef504cc..e0feb27f 100644 --- a/ytdl_subscribe/validators/base/strict_dict_validator.py +++ b/ytdl_subscribe/validators/base/strict_dict_validator.py @@ -10,21 +10,21 @@ class StrictDictValidator(DictValidator): Validates dictionary-based fields with required and optional keys. """ - required_keys: Set[str] = set() - optional_keys: Set[str] = set() - allow_extra_keys = False + _required_keys: Set[str] = set() + _optional_keys: Set[str] = set() + _allow_extra_keys = False def __init__(self, name, value): super().__init__(name, value) - if len(self.allowed_keys) == 0: + if len(self._allowed_keys) == 0: raise ValueError( "No required or optional keys defined when using a StrictDictValidator. " "Should be using DictValidator instead." ) # Ensure all required keys are present - for required_key in self.required_keys: + for required_key in self._required_keys: if required_key not in self.value: raise self._validation_exception( f"missing the required field '{required_key}'" @@ -34,24 +34,24 @@ class StrictDictValidator(DictValidator): if not self.dict: raise self._validation_exception( f"at least one of the following fields must be defined: " - f"{', '.join(self.optional_keys)}'" + f"{', '.join(self._optional_keys)}'" ) # Ensure all keys are either required or optional keys if no extra field are allowed - if not self.allow_extra_keys: + if not self._allow_extra_keys: for object_key in self.keys: - if object_key not in self.allowed_keys: + if object_key not in self._allowed_keys: error_msg = ( f"'{self.name}' contains the field '{object_key}' which is not allowed. " - f"Allowed fields: {', '.join(self.allowed_keys)}" + f"Allowed fields: {', '.join(self._allowed_keys)}" ) raise ValidationException(error_msg) @property - def allowed_keys(self) -> List[str]: + def _allowed_keys(self) -> List[str]: """ Returns ------- Sorted list of required and optional keys """ - return sorted(list(self.required_keys.union(self.optional_keys))) + return sorted(list(self._required_keys.union(self._optional_keys))) diff --git a/ytdl_subscribe/validators/base/string_formatter_validator.py b/ytdl_subscribe/validators/base/string_formatter_validator.py index d82bafa6..01283712 100644 --- a/ytdl_subscribe/validators/base/string_formatter_validator.py +++ b/ytdl_subscribe/validators/base/string_formatter_validator.py @@ -11,7 +11,7 @@ class StringFormatterValidator(StringValidator): Ensures user-created formatter strings are valid """ - expected_value_type_name = "format string" + _expected_value_type_name = "format string" FIELDS_VALIDATOR = re.compile(r"{([a-z_]+?)}") diff --git a/ytdl_subscribe/validators/base/string_select_validator.py b/ytdl_subscribe/validators/base/string_select_validator.py index fae23e30..75346b8f 100644 --- a/ytdl_subscribe/validators/base/string_select_validator.py +++ b/ytdl_subscribe/validators/base/string_select_validator.py @@ -11,12 +11,12 @@ class StringSelectValidator(StringValidator): Ensures strings have selected one of the discrete allowed values. """ - select_values: Set[str] = set() + _select_values: Set[str] = set() def __init__(self, name, value: str): super().__init__(name=name, value=value) - if self.value not in self.select_values: + if self.value not in self._select_values: raise self._validation_exception( - f"Must be one of the following values: {', '.join(self.select_values)}" + f"Must be one of the following values: {', '.join(self._select_values)}" ) diff --git a/ytdl_subscribe/validators/base/validators.py b/ytdl_subscribe/validators/base/validators.py index 03ce8531..8ba80425 100644 --- a/ytdl_subscribe/validators/base/validators.py +++ b/ytdl_subscribe/validators/base/validators.py @@ -15,18 +15,18 @@ class Validator: """ # If the value is not this expected type, error - expected_value_type: Type = object + _expected_value_type: Type = object # When raising an error, call the type this value instead of its python name - expected_value_type_name: Optional[str] = None + _expected_value_type_name: Optional[str] = None def __init__(self, name: str, value: Any): self.name = name self._value = value - if not isinstance(self._value, self.expected_value_type): - expected_value_type_name = self.expected_value_type_name or str( - self.expected_value_type + if not isinstance(self._value, self._expected_value_type): + expected_value_type_name = self._expected_value_type_name or str( + self._expected_value_type ) raise self._validation_exception( error_message=f"should be of type {expected_value_type_name}." @@ -61,8 +61,8 @@ class BoolValidator(Validator): Validates boolean fields. """ - expected_value_type: Type = bool - expected_value_type_name = "boolean" + _expected_value_type: Type = bool + _expected_value_type_name = "boolean" @property def value(self) -> bool: @@ -79,8 +79,8 @@ class StringValidator(Validator): Validates string fields. """ - expected_value_type: Type = str - expected_value_type_name = "string" + _expected_value_type: Type = str + _expected_value_type_name = "string" @property def value(self) -> str: @@ -101,8 +101,8 @@ class DictValidator(Validator): a yaml. """ - expected_value_type = dict - expected_value_type_name = "object" + _expected_value_type = dict + _expected_value_type_name = "object" @property def dict(self) -> dict: diff --git a/ytdl_subscribe/validators/config/config_validator.py b/ytdl_subscribe/validators/config/config_validator.py index 60da0bc4..d303d519 100644 --- a/ytdl_subscribe/validators/config/config_validator.py +++ b/ytdl_subscribe/validators/config/config_validator.py @@ -8,7 +8,7 @@ from ytdl_subscribe.validators.base.validators import StringValidator class ConfigValidator(StrictDictValidator): - required_keys = {"working_directory", "presets"} + _required_keys = {"working_directory", "presets"} def __init__(self, name: str, value: Any): super().__init__(name, value) diff --git a/ytdl_subscribe/validators/config/metadata_options/id3_validator.py b/ytdl_subscribe/validators/config/metadata_options/id3_validator.py index 300dd0ee..18d7c7df 100644 --- a/ytdl_subscribe/validators/config/metadata_options/id3_validator.py +++ b/ytdl_subscribe/validators/config/metadata_options/id3_validator.py @@ -7,12 +7,12 @@ from ytdl_subscribe.validators.base.validators import StringValidator class Id3VersionValidator(StringSelectValidator): - select_values = {"2.3", "2.4"} + _select_values = {"2.3", "2.4"} class Id3Validator(StrictDictValidator): - required_keys = {"id3_version", "tags"} - optional_keys = {"multi_value_separator"} + _required_keys = {"id3_version", "tags"} + _optional_keys = {"multi_value_separator"} def __init__(self, name, value): super().__init__(name, value) diff --git a/ytdl_subscribe/validators/config/metadata_options/metadata_options_validator.py b/ytdl_subscribe/validators/config/metadata_options/metadata_options_validator.py index b08eee39..e30ca06c 100644 --- a/ytdl_subscribe/validators/config/metadata_options/metadata_options_validator.py +++ b/ytdl_subscribe/validators/config/metadata_options/metadata_options_validator.py @@ -1,15 +1,10 @@ -from typing import Optional - from ytdl_subscribe.validators.base.strict_dict_validator import StrictDictValidator -from ytdl_subscribe.validators.base.string_formatter_validator import ( - StringFormatterValidator, -) from ytdl_subscribe.validators.config.metadata_options.id3_validator import Id3Validator from ytdl_subscribe.validators.config.metadata_options.nfo_validator import NFOValidator class MetadataOptionsValidator(StrictDictValidator): - optional_keys = {"id3", "nfo"} + _optional_keys = {"id3", "nfo"} def __init__(self, name, value): super().__init__(name, value) diff --git a/ytdl_subscribe/validators/config/metadata_options/nfo_validator.py b/ytdl_subscribe/validators/config/metadata_options/nfo_validator.py index a56c7d5f..93e4568b 100644 --- a/ytdl_subscribe/validators/config/metadata_options/nfo_validator.py +++ b/ytdl_subscribe/validators/config/metadata_options/nfo_validator.py @@ -5,12 +5,10 @@ from ytdl_subscribe.validators.base.string_formatter_validator import ( from ytdl_subscribe.validators.base.string_formatter_validator import ( StringFormatterValidator, ) -from ytdl_subscribe.validators.base.string_select_validator import StringSelectValidator -from ytdl_subscribe.validators.base.validators import StringValidator class NFOValidator(StrictDictValidator): - required_keys = {"nfo_name", "nfo_root", "tags"} + _required_keys = {"nfo_name", "nfo_root", "tags"} def __init__(self, name, value): super().__init__(name, value) diff --git a/ytdl_subscribe/validators/config/output_options/output_options_validator.py b/ytdl_subscribe/validators/config/output_options/output_options_validator.py index 5d22da86..a188060c 100644 --- a/ytdl_subscribe/validators/config/output_options/output_options_validator.py +++ b/ytdl_subscribe/validators/config/output_options/output_options_validator.py @@ -8,12 +8,12 @@ from ytdl_subscribe.validators.base.string_select_validator import StringSelectV class ConvertThumbnailValidator(StringSelectValidator): - select_values = {"jpeg"} + _select_values = {"jpeg"} class OutputOptionsValidator(StrictDictValidator): - required_keys = {"output_directory", "file_name"} - optional_keys = {"convert_thumbnail", "thumbnail_name"} + _required_keys = {"output_directory", "file_name"} + _optional_keys = {"convert_thumbnail", "thumbnail_name"} def __init__(self, name, value): super().__init__(name, value) diff --git a/ytdl_subscribe/validators/config/preset_validator.py b/ytdl_subscribe/validators/config/preset_validator.py index d827519f..8805969b 100644 --- a/ytdl_subscribe/validators/config/preset_validator.py +++ b/ytdl_subscribe/validators/config/preset_validator.py @@ -47,22 +47,22 @@ class OverridesValidator(DictFormatterValidator): class PresetValidator(StrictDictValidator): - subscription_source_validator_mapping: Dict[str, Type[SourceValidator]] = { + _subscription_source_validator_mapping: Dict[str, Type[SourceValidator]] = { "soundcloud": SoundcloudSourceValidator, "youtube": YoutubeSourceValidator, } - required_keys = {"output_options"} - optional_keys = { + _required_keys = {"output_options"} + _optional_keys = { "metadata_options", "ytdl_options", "overrides", - *subscription_source_validator_mapping.keys(), + *_subscription_source_validator_mapping.keys(), } @property def available_sources(self) -> List[str]: - return sorted(list(self.subscription_source_validator_mapping.keys())) + return sorted(list(self._subscription_source_validator_mapping.keys())) def __validate_and_get_subscription_source(self) -> Tuple[str, SourceValidator]: subscription_source: Optional[SourceValidator] = None @@ -75,10 +75,10 @@ class PresetValidator(StrictDictValidator): f"{', '.join(self.available_sources)}" ) - if key in self.subscription_source_validator_mapping: + if key in self._subscription_source_validator_mapping: subscription_source_name = key subscription_source = self.validate_key( - key=key, validator=self.subscription_source_validator_mapping[key] + key=key, validator=self._subscription_source_validator_mapping[key] ) # If subscription source was not set, error diff --git a/ytdl_subscribe/validators/config/sources/soundcloud_validators.py b/ytdl_subscribe/validators/config/sources/soundcloud_validators.py index 97d71cf9..64e7c565 100644 --- a/ytdl_subscribe/validators/config/sources/soundcloud_validators.py +++ b/ytdl_subscribe/validators/config/sources/soundcloud_validators.py @@ -7,7 +7,7 @@ from ytdl_subscribe.validators.config.sources.source_validator import SourceVali class SoundcloudAlbumsAndSinglesDownloadValidator(DownloadStrategyValidator): - required_keys = {"username"} + _required_keys = {"username"} def __init__(self, name, value): super().__init__(name, value) @@ -15,7 +15,7 @@ class SoundcloudAlbumsAndSinglesDownloadValidator(DownloadStrategyValidator): class SoundcloudSourceValidator(SourceValidator): - optional_keys = {"skip_premiere_tracks"} + _optional_keys = {"skip_premiere_tracks"} download_strategy_validator_mapping = { "albums_and_singles": SoundcloudAlbumsAndSinglesDownloadValidator diff --git a/ytdl_subscribe/validators/config/sources/source_validator.py b/ytdl_subscribe/validators/config/sources/source_validator.py index 609ab601..c13676a9 100644 --- a/ytdl_subscribe/validators/config/sources/source_validator.py +++ b/ytdl_subscribe/validators/config/sources/source_validator.py @@ -13,10 +13,10 @@ class DownloadStrategyValidator(StrictDictValidator): class SourceValidator(StrictDictValidator): # All media sources must define a download strategy - required_keys = {"download_strategy"} + _required_keys = {"download_strategy"} # Extra fields will be strict-validated using other StictDictValidators - allow_extra_keys = True + _allow_extra_keys = True download_strategy_validator_mapping: Dict[str, Type[DownloadStrategyValidator]] = {} @@ -34,7 +34,7 @@ class SourceValidator(StrictDictValidator): # 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_keys: + for key_to_delete in self._allowed_keys: del download_strategy_dict[key_to_delete] download_strategy_class = self.download_strategy_validator_mapping[ diff --git a/ytdl_subscribe/validators/config/sources/youtube_validators.py b/ytdl_subscribe/validators/config/sources/youtube_validators.py index 53115bc3..1f5467ca 100644 --- a/ytdl_subscribe/validators/config/sources/youtube_validators.py +++ b/ytdl_subscribe/validators/config/sources/youtube_validators.py @@ -8,7 +8,7 @@ from ytdl_subscribe.validators.config.sources.source_validator import SourceVali class YoutubePlaylistDownloadValidator(DownloadStrategyValidator): - required_keys = {"playlist_id"} + _required_keys = {"playlist_id"} def __init__(self, name, value): super().__init__(name, value) diff --git a/ytdl_subscribe/validators/config/subscription_validator.py b/ytdl_subscribe/validators/config/subscription_validator.py index 46b09874..1347d6ba 100644 --- a/ytdl_subscribe/validators/config/subscription_validator.py +++ b/ytdl_subscribe/validators/config/subscription_validator.py @@ -27,8 +27,10 @@ class SubscriptionValidator(StrictDictValidator): A Subscription is a preset but overrides it with specific values """ - required_keys = {"preset"} - optional_keys = PresetValidator.required_keys.union(PresetValidator.optional_keys) + _required_keys = {"preset"} + _optional_keys = PresetValidator._required_keys.union( + PresetValidator._optional_keys + ) def __init__(self, config: ConfigValidator, name: str, value: Any): super().__init__(name, value)