override format string, thumbnail hotfix
This commit is contained in:
parent
e3239153ec
commit
fb7993cf70
7 changed files with 111 additions and 7 deletions
|
|
@ -7,7 +7,6 @@ from typing import Generic
|
|||
from typing import Optional
|
||||
from typing import Type
|
||||
from typing import TypeVar
|
||||
from typing import overload
|
||||
|
||||
import dicttoxml
|
||||
import music_tag
|
||||
|
|
@ -169,6 +168,19 @@ class Subscription(Generic[S], ABC):
|
|||
if self.output_options.thumbnail_name:
|
||||
source_thumbnail_path = entry.thumbnail_path(relative_directory=self.working_directory)
|
||||
|
||||
# Bug that mismatches webp and jpg extensions. Try to hotfix here
|
||||
if not os.path.isfile(source_thumbnail_path):
|
||||
actual_thumbnail_ext = ".webp"
|
||||
if entry.thumbnail_ext == "webp":
|
||||
actual_thumbnail_ext = ".jpg"
|
||||
|
||||
source_thumbnail_path = source_thumbnail_path.replace(
|
||||
f".{entry.thumbnail_ext}", actual_thumbnail_ext
|
||||
)
|
||||
if not os.path.isfile(source_thumbnail_path):
|
||||
# TODO: make more formal
|
||||
raise ValueError("Youtube thumbnails are a lie")
|
||||
|
||||
output_thumbnail_name = self._apply_formatter(
|
||||
formatter=self.output_options.thumbnail_name, entry=entry
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ from typing import final
|
|||
from ytdl_subscribe.validators.base.validators import LiteralDictValidator
|
||||
from ytdl_subscribe.validators.base.validators import Validator
|
||||
from ytdl_subscribe.validators.exceptions import StringFormattingException
|
||||
from ytdl_subscribe.validators.exceptions import StringFormattingVariableNotFoundException
|
||||
|
||||
|
||||
class StringFormatterValidator(Validator):
|
||||
|
|
@ -89,7 +90,7 @@ class StringFormatterValidator(Validator):
|
|||
raise self._validation_exception(
|
||||
f"Format variable '{variable_name}' does not exist. "
|
||||
f"Available variables: {available_fields}",
|
||||
exception_class=StringFormattingException,
|
||||
exception_class=StringFormattingVariableNotFoundException,
|
||||
)
|
||||
|
||||
return StringFormatterValidator(
|
||||
|
|
@ -119,6 +120,12 @@ class StringFormatterValidator(Validator):
|
|||
return formatter.format_string
|
||||
|
||||
|
||||
class OverridesStringFormatterValidator(StringFormatterValidator):
|
||||
"""
|
||||
A string formatter that should strictly use overrides that resolve without any entry variables.
|
||||
"""
|
||||
|
||||
|
||||
class DictFormatterValidator(LiteralDictValidator):
|
||||
"""
|
||||
Validates a dictionary made up of key: string_formatters
|
||||
|
|
|
|||
|
|
@ -103,6 +103,10 @@ class DictValidator(Validator):
|
|||
_expected_value_type = dict
|
||||
_expected_value_type_name = "object"
|
||||
|
||||
def __init__(self, name, value):
|
||||
super().__init__(name, value)
|
||||
self.__validator_dict: Dict[str, Validator] = {}
|
||||
|
||||
@final
|
||||
@property
|
||||
def _dict(self) -> dict:
|
||||
|
|
@ -113,6 +117,15 @@ class DictValidator(Validator):
|
|||
"""
|
||||
return self._value
|
||||
|
||||
@final
|
||||
@property
|
||||
def _validator_dict(self) -> Dict[str, Validator]:
|
||||
"""
|
||||
Returns dict containing names and validators of any keys that were validated.
|
||||
This allows top-level validators to recursively search a dict validator.
|
||||
"""
|
||||
return self.__validator_dict
|
||||
|
||||
@final
|
||||
@property
|
||||
def _keys(self) -> List[str]:
|
||||
|
|
@ -147,11 +160,15 @@ class DictValidator(Validator):
|
|||
if key not in self._dict and default is None:
|
||||
raise self._validation_exception(f"{key} is missing when it should be present.")
|
||||
|
||||
return validator(
|
||||
name=f"{self._name}.{key}",
|
||||
validator_name = f"{self._name}.{key}"
|
||||
validator_instance = validator(
|
||||
name=validator_name,
|
||||
value=self._dict.get(key, default),
|
||||
)
|
||||
|
||||
self.__validator_dict[validator_name] = validator_instance
|
||||
return validator_instance
|
||||
|
||||
@final
|
||||
def _validate_key_if_present(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
from ytdl_subscribe.validators.base.strict_dict_validator import StrictDictValidator
|
||||
from ytdl_subscribe.validators.base.string_formatter_validators import DictFormatterValidator
|
||||
from ytdl_subscribe.validators.base.string_formatter_validators import (
|
||||
OverridesStringFormatterValidator,
|
||||
)
|
||||
from ytdl_subscribe.validators.base.string_formatter_validators import StringFormatterValidator
|
||||
|
||||
|
||||
|
|
@ -12,3 +15,11 @@ class NFOValidator(StrictDictValidator):
|
|||
self.nfo_name = self._validate_key(key="nfo_name", validator=StringFormatterValidator)
|
||||
self.nfo_root = self._validate_key(key="nfo_root", validator=StringFormatterValidator)
|
||||
self.tags = self._validate_key(key="tags", validator=DictFormatterValidator)
|
||||
|
||||
|
||||
class OutputDirectoryNFOValidator(NFOValidator):
|
||||
def __init__(self, name, value):
|
||||
super().__init__(name, value)
|
||||
self.nfo_name = self._validate_key(
|
||||
key="nfo_name", validator=OverridesStringFormatterValidator
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
from ytdl_subscribe.validators.base.strict_dict_validator import StrictDictValidator
|
||||
from ytdl_subscribe.validators.base.string_formatter_validators import (
|
||||
OverridesStringFormatterValidator,
|
||||
)
|
||||
from ytdl_subscribe.validators.base.string_formatter_validators import StringFormatterValidator
|
||||
from ytdl_subscribe.validators.base.string_select_validator import StringSelectValidator
|
||||
|
||||
|
|
@ -18,13 +21,16 @@ class OutputOptionsValidator(StrictDictValidator):
|
|||
def __init__(self, name, value):
|
||||
super().__init__(name, value)
|
||||
|
||||
self.output_directory: StringFormatterValidator = self._validate_key(
|
||||
key="output_directory", validator=StringFormatterValidator
|
||||
# Output directory should resolve without any entry variables.
|
||||
# This is to check the directory for any download-archives before any downloads begin
|
||||
self.output_directory: OverridesStringFormatterValidator = self._validate_key(
|
||||
key="output_directory", validator=OverridesStringFormatterValidator
|
||||
)
|
||||
|
||||
# file name and thumbnails however can use entry variables
|
||||
self.file_name: StringFormatterValidator = self._validate_key(
|
||||
key="file_name", validator=StringFormatterValidator
|
||||
)
|
||||
|
||||
self.convert_thumbnail = self._validate_key_if_present(
|
||||
key="convert_thumbnail", validator=ConvertThumbnailValidator
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@ from typing import Optional
|
|||
from typing import Type
|
||||
|
||||
from ytdl_subscribe.validators.base.strict_dict_validator import StrictDictValidator
|
||||
from ytdl_subscribe.validators.base.string_formatter_validators import (
|
||||
OverridesStringFormatterValidator,
|
||||
)
|
||||
from ytdl_subscribe.validators.base.validators import DictValidator
|
||||
from ytdl_subscribe.validators.base.validators import Validator
|
||||
from ytdl_subscribe.validators.config.metadata_options.metadata_options_validator import (
|
||||
MetadataOptionsValidator,
|
||||
)
|
||||
|
|
@ -25,6 +30,7 @@ from ytdl_subscribe.validators.config.source_options.source_validators import So
|
|||
from ytdl_subscribe.validators.config.ytdl_options.ytdl_options_validator import (
|
||||
YTDLOptionsValidator,
|
||||
)
|
||||
from ytdl_subscribe.validators.exceptions import StringFormattingVariableNotFoundException
|
||||
from ytdl_subscribe.validators.exceptions import ValidationException
|
||||
|
||||
PRESET_SOURCE_VALIDATOR_MAPPING: Dict[str, Type[DownloadStrategyValidator]] = {
|
||||
|
|
@ -74,6 +80,43 @@ class PresetValidator(StrictDictValidator):
|
|||
|
||||
return download_strategy_validator.source_validator
|
||||
|
||||
def __validate_override_string_formatter_validator(
|
||||
self, formatter_validator: OverridesStringFormatterValidator
|
||||
):
|
||||
# Gather all resolvable override variables
|
||||
resolvable_override_variables: List[str] = []
|
||||
for name, override_variable in self.overrides.dict.items():
|
||||
try:
|
||||
_ = override_variable.apply_formatter(self.overrides.dict_with_format_strings)
|
||||
except StringFormattingVariableNotFoundException:
|
||||
continue
|
||||
resolvable_override_variables.append(name)
|
||||
|
||||
for variable_name in formatter_validator.format_variables:
|
||||
if variable_name not in resolvable_override_variables:
|
||||
raise StringFormattingVariableNotFoundException(
|
||||
f"This variable can only use override variables that resolve without needing "
|
||||
f"variables from a downloaded file. The only override variables defined that "
|
||||
f"meet this condition are: {', '.join(sorted(resolvable_override_variables))}"
|
||||
)
|
||||
|
||||
def __recursive_preset_validate(
|
||||
self, validator_dict: Optional[Dict[str, Validator]] = None
|
||||
) -> None:
|
||||
"""
|
||||
Ensure all OverridesStringFormatterValidator's only contain variables from the overrides
|
||||
and resolve.
|
||||
"""
|
||||
if validator_dict is None:
|
||||
validator_dict = self._validator_dict
|
||||
|
||||
for name, validator in validator_dict.items():
|
||||
if isinstance(validator, DictValidator):
|
||||
self.__recursive_preset_validate(validator._validator_dict)
|
||||
|
||||
if isinstance(validator, OverridesStringFormatterValidator):
|
||||
self.__validate_override_string_formatter_validator(validator)
|
||||
|
||||
def __init__(self, name: str, value: Any):
|
||||
super().__init__(name=name, value=value)
|
||||
|
||||
|
|
@ -94,3 +137,7 @@ class PresetValidator(StrictDictValidator):
|
|||
self.overrides = self._validate_key(
|
||||
key="overrides", validator=OverridesValidator, default={}
|
||||
)
|
||||
|
||||
# After all options are initialized, perform a recursive post-validate that requires
|
||||
# values from multiple validators
|
||||
self.__recursive_preset_validate()
|
||||
|
|
|
|||
|
|
@ -4,3 +4,7 @@ class ValidationException(ValueError):
|
|||
|
||||
class StringFormattingException(ValidationException):
|
||||
"""Tried to format a string but failed due to user misconfigured variables"""
|
||||
|
||||
|
||||
class StringFormattingVariableNotFoundException(StringFormattingException):
|
||||
"""Tried to format a string but the variable was not found"""
|
||||
|
|
|
|||
Loading…
Reference in a new issue