[BACKEND] output_directory_nfo_tags to support source vars

This commit is contained in:
Jesse Bannon 2022-09-17 09:05:54 -07:00
parent 46c14bd842
commit 030974c074
8 changed files with 28 additions and 227 deletions

View file

@ -131,10 +131,6 @@ class Preset(StrictDictValidator):
def _source_variables(self) -> List[str]:
return self.downloader.downloader_entry_type.source_variables()
@property
def _added_override_variables(self) -> List[str]:
return self.downloader.added_override_variables()
def __validate_and_get_downloader(self, downloader_source: str) -> Type[Downloader]:
return self._validate_key(key=downloader_source, validator=DownloadStrategyValidator).get(
downloader_source=downloader_source
@ -225,10 +221,7 @@ class Preset(StrictDictValidator):
formatter_validator: Union[StringFormatterValidator, OverridesStringFormatterValidator],
):
# Set the formatter variables to be the overrides
variable_dict = dict(
self.overrides.dict_with_format_strings,
**{added_override: "dummy_string" for added_override in self._added_override_variables},
)
variable_dict = copy.deepcopy(self.overrides.dict_with_format_strings)
# If the formatter supports source variables, set the formatter variables to include
# both source and override variables

View file

@ -121,21 +121,6 @@ class Overrides(DictFormatterValidator):
sanitize=True,
)
def add_override_variables(self, variables_to_add: Dict[str, str]) -> None:
"""
Parameters
----------
variables_to_add
Override variables to add
"""
for key_name, override_var_value in variables_to_add.items():
for sanitize in [False, True]:
self._add_override_variable(
key_name=key_name,
format_string=override_var_value,
sanitize=sanitize,
)
def apply_formatter(
self,
formatter: StringFormatterValidator,

View file

@ -111,15 +111,6 @@ class Downloader(DownloadArchiver, Generic[DownloaderOptionsT, DownloaderEntryT]
"""
return {"ignoreerrors": True}
@classmethod
def added_override_variables(cls) -> List[str]:
"""
Returns
-------
List of override variables that this downloader adds
"""
return []
def __init__(
self,
download_options: DownloaderOptionsT,

View file

@ -1,7 +1,6 @@
from pathlib import Path
from typing import Dict
from typing import Generator
from typing import List
from typing import Optional
from ytdl_sub.downloaders.downloader import download_logger
@ -109,20 +108,6 @@ class YoutubeChannelDownloader(YoutubeDownloader[YoutubeChannelDownloaderOptions
},
)
@classmethod
def added_override_variables(cls) -> List[str]:
"""
Adds the following :ref:`override <overrides>` variables:
.. code-block:: yaml
overrides:
source_uploader: # The channel's name. NOTE: sometimes it's empty, use with caution
source_title: # The channel's name
source_description: # The channel's description
"""
return ["source_uploader", "source_title", "source_description"]
# pylint: enable=line-too-long
@property
@ -135,20 +120,7 @@ class YoutubeChannelDownloader(YoutubeDownloader[YoutubeChannelDownloaderOptions
"""
Downloads all videos from a channel
"""
collection_url = self.collection.collection_urls.list[0]
_, orphans = super()._download_url_metadata(collection_url=collection_url)
assert not orphans
# TODO: Handle this better
self.overrides.add_override_variables(
variables_to_add={
"source_uploader": self.channel.kwargs_get("uploader", "__failed_to_scrape__"),
"source_title": self.channel.kwargs("title"),
"source_description": self.channel.kwargs_get("description", ""),
}
)
for entry in super()._download(parents=self.parents):
for entry in super().download():
yield entry.to_type(YoutubeVideo)
def _download_thumbnail(

View file

@ -1,6 +1,5 @@
from typing import Dict
from typing import Generator
from typing import List
from ytdl_sub.downloaders.generic.collection_validator import CollectionValidator
from ytdl_sub.downloaders.youtube.abc import YoutubeDownloader
@ -74,20 +73,6 @@ class YoutubePlaylistDownloader(
**{"break_on_existing": True},
)
@classmethod
def added_override_variables(cls) -> List[str]:
"""
Adds the following :ref:`override <overrides>` variables:
.. code-block:: yaml
overrides:
source_uploader: # The playlist's owner's channel name. NOTE: sometimes it's empty, use with caution
source_title: # The playlist's title
source_description: # The playlist's description
"""
return ["source_uploader", "source_title", "source_description"]
# pylint: enable=line-too-long
@property
@ -100,18 +85,5 @@ class YoutubePlaylistDownloader(
"""
Downloads all videos in a Youtube playlist.
"""
collection_url = self.collection.collection_urls.list[0]
_, orphans = super()._download_url_metadata(collection_url)
assert not orphans
# TODO: Handle this better
self.overrides.add_override_variables(
variables_to_add={
"source_title": self.playlist.title,
"source_uploader": self.playlist.kwargs_get("uploader", "__failed_to_scrape__"),
"source_description": self.playlist.kwargs_get("description", ""),
}
)
for entry in super()._download(parents=self.parents):
for entry in super().download():
yield entry.to_type(YoutubePlaylistVideo)

View file

@ -3,11 +3,8 @@ from abc import ABC
from collections import defaultdict
from pathlib import Path
from typing import Dict
from typing import Generic
from typing import List
from typing import Optional
from typing import Type
from typing import TypeVar
from ytdl_sub.entries.entry import Entry
from ytdl_sub.plugins.plugin import Plugin
@ -18,37 +15,25 @@ from ytdl_sub.utils.xml import to_max_3_byte_utf8_dict
from ytdl_sub.utils.xml import to_max_3_byte_utf8_string
from ytdl_sub.utils.xml import to_xml
from ytdl_sub.validators.nfo_validators import NfoTagsValidator
from ytdl_sub.validators.nfo_validators import SharedNfoTagsValidator
from ytdl_sub.validators.nfo_validators import TDictFormatterValidator
from ytdl_sub.validators.nfo_validators import TStringFormatterValidator
from ytdl_sub.validators.string_formatter_validators import DictFormatterValidator
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
from ytdl_sub.validators.validators import BoolValidator
TSharedNfoTagsValidator = TypeVar("TSharedNfoTagsValidator", bound=SharedNfoTagsValidator)
class SharedNfoTagsOptions(
PluginOptions,
Generic[TStringFormatterValidator, TDictFormatterValidator, TSharedNfoTagsValidator],
ABC,
):
class SharedNfoTagsOptions(PluginOptions):
"""
Shared code between NFO tags and Ouptut Directory NFO Tags
"""
_formatter_validator: Type[TStringFormatterValidator]
_tags_validator: Type[TSharedNfoTagsValidator]
_required_keys = {"nfo_name", "nfo_root", "tags"}
_optional_keys = {"kodi_safe"}
def __init__(self, name, value):
super().__init__(name, value)
self._nfo_name = self._validate_key(key="nfo_name", validator=self._formatter_validator)
self._nfo_root = self._validate_key(key="nfo_root", validator=self._formatter_validator)
self._tags = self._validate_key(key="tags", validator=self._tags_validator)
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=NfoTagsValidator)
self._kodi_safe = self._validate_key_if_present(
key="kodi_safe", validator=BoolValidator, default=False
).value
@ -68,7 +53,7 @@ class SharedNfoTagsOptions(
return self._nfo_root
@property
def tags(self) -> TSharedNfoTagsValidator:
def tags(self) -> NfoTagsValidator:
"""
OVERRIDE DOC IN CHILD CLASSES
"""
@ -84,15 +69,7 @@ class SharedNfoTagsOptions(
return self._kodi_safe
class SharedNfoTagsPlugin(
Plugin[
SharedNfoTagsOptions[
TStringFormatterValidator, TDictFormatterValidator, TSharedNfoTagsValidator
]
],
Generic[TStringFormatterValidator, TDictFormatterValidator, TSharedNfoTagsValidator],
ABC,
):
class SharedNfoTagsPlugin(Plugin[SharedNfoTagsOptions], ABC):
"""
Shared code between NFO tags and Ouptut Directory NFO Tags
"""
@ -174,9 +151,7 @@ class SharedNfoTagsPlugin(
self.save_file(file_name=nfo_file_name, file_metadata=nfo_metadata, entry=entry)
class NfoTagsOptions(
SharedNfoTagsOptions[StringFormatterValidator, DictFormatterValidator, NfoTagsValidator]
):
class NfoTagsOptions(SharedNfoTagsOptions):
"""
Adds an NFO file for every download file. An NFO file is simply an XML file
with a ``.nfo`` extension. You can add any values into the NFO.
@ -254,9 +229,7 @@ class NfoTagsOptions(
return self._tags
class NfoTagsPlugin(
SharedNfoTagsPlugin[StringFormatterValidator, DictFormatterValidator, NfoTagsValidator]
):
class NfoTagsPlugin(SharedNfoTagsPlugin):
plugin_options_type = NfoTagsOptions
def post_process_entry(self, entry: Entry) -> None:

View file

@ -1,16 +1,10 @@
from ytdl_sub.plugins.nfo_tags import NfoTagsValidator
from ytdl_sub.plugins.nfo_tags import SharedNfoTagsOptions
from ytdl_sub.plugins.nfo_tags import SharedNfoTagsPlugin
from ytdl_sub.validators.nfo_validators import NfoOverrideTagsValidator
from ytdl_sub.validators.string_formatter_validators import OverridesDictFormatterValidator
from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
class OutputDirectoryNfoTagsOptions(
SharedNfoTagsOptions[
OverridesStringFormatterValidator, OverridesDictFormatterValidator, NfoOverrideTagsValidator
]
):
class OutputDirectoryNfoTagsOptions(SharedNfoTagsOptions):
"""
Adds a single NFO file in the output directory. An NFO file is simply an XML file with a
``.nfo`` extension. You can add any strings or override variables into this NFO.
@ -31,12 +25,8 @@ class OutputDirectoryNfoTagsOptions(
kodi_safe: False
"""
_formatter_validator = OverridesStringFormatterValidator
_dict_formatter_validator = OverridesDictFormatterValidator
_tags_validator = NfoOverrideTagsValidator
@property
def nfo_root(self) -> OverridesStringFormatterValidator:
def nfo_root(self) -> StringFormatterValidator:
"""
The root tag of the NFO's XML. In the usage above, it would look like
@ -49,9 +39,7 @@ class OutputDirectoryNfoTagsOptions(
return self._nfo_root
@property
def tags(
self,
) -> NfoTagsValidator:
def tags(self) -> NfoTagsValidator:
"""
Tags within the nfo_root tag. In the usage above, it would look like
@ -86,13 +74,7 @@ class OutputDirectoryNfoTagsOptions(
return self._tags
class OutputDirectoryNfoTagsPlugin(
SharedNfoTagsPlugin[
OverridesStringFormatterValidator,
OverridesDictFormatterValidator,
OutputDirectoryNfoTagsOptions,
]
):
class OutputDirectoryNfoTagsPlugin(SharedNfoTagsPlugin):
plugin_options_type = OutputDirectoryNfoTagsOptions
def post_process_subscription(self):

View file

@ -1,43 +1,27 @@
from abc import ABC
from collections import defaultdict
from typing import Dict
from typing import Generic
from typing import List
from typing import Type
from typing import TypeVar
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
from ytdl_sub.validators.string_formatter_validators import DictFormatterValidator
from ytdl_sub.validators.string_formatter_validators import ListFormatterValidator
from ytdl_sub.validators.string_formatter_validators import ListOverridesFormatterValidator
from ytdl_sub.validators.string_formatter_validators import OverridesDictFormatterValidator
from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
from ytdl_sub.validators.validators import DictValidator
from ytdl_sub.validators.validators import ListValidator
TStringFormatterValidator = TypeVar("TStringFormatterValidator", bound=StringFormatterValidator)
TDictFormatterValidator = TypeVar("TDictFormatterValidator", bound=DictFormatterValidator)
class _NfoTagsWithAttributesValidator(
StrictDictValidator, Generic[TStringFormatterValidator, TDictFormatterValidator], ABC
):
class NfoTagsWithAttributesValidator(StrictDictValidator):
_required_keys = {"attributes", "tag"}
formatter_validator: Type[TStringFormatterValidator]
dict_formatter_validator: Type[TDictFormatterValidator]
def __init__(self, name, value):
super().__init__(name, value)
self._attributes = self._validate_key(
key="attributes", validator=self.dict_formatter_validator
)
self._tag = self._validate_key(key="tag", validator=self.formatter_validator)
self._attributes = self._validate_key(key="attributes", validator=DictFormatterValidator)
self._tag = self._validate_key(key="tag", validator=StringFormatterValidator)
@property
def attributes(self) -> TDictFormatterValidator:
def attributes(self) -> DictFormatterValidator:
"""
Returns
-------
@ -46,7 +30,7 @@ class _NfoTagsWithAttributesValidator(
return self._attributes
@property
def tag(self) -> TStringFormatterValidator:
def tag(self) -> StringFormatterValidator:
"""
Returns
-------
@ -55,59 +39,18 @@ class _NfoTagsWithAttributesValidator(
return self._tag
class NfoTagsWithAttributesValidator(
_NfoTagsWithAttributesValidator[StringFormatterValidator, DictFormatterValidator]
):
"""TagsWithAttributes for the entry NFO validator"""
formatter_validator = StringFormatterValidator
dict_formatter_validator = DictFormatterValidator
class NfoTagsWithAttributesListValidator(ListValidator[NfoTagsWithAttributesValidator]):
"""TagsWithAttributes list for the entry NFO validator"""
_inner_list_type = NfoTagsWithAttributesValidator
class NfoOverrideTagsWithAttributesValidator(
_NfoTagsWithAttributesValidator[
OverridesStringFormatterValidator, OverridesDictFormatterValidator
]
):
"""TagsWithAttributes for the output directory NFO validator"""
formatter_validator = OverridesStringFormatterValidator
dict_formatter_validator = OverridesDictFormatterValidator
class NfoOverrideTagsWithAttributesListValidator(
ListValidator[NfoOverrideTagsWithAttributesValidator]
):
"""TagsWithAttributes list for the output directory NFO validator"""
_inner_list_type = NfoOverrideTagsWithAttributesValidator
# Generic TagsWithAttribute to use for SharedNfoTagsValidator
TNfoTagsWithAttributesValidator = _NfoTagsWithAttributesValidator[
TStringFormatterValidator, TDictFormatterValidator
]
# List validators
TNfoTagsWithAttributesListValidator = ListValidator[TNfoTagsWithAttributesValidator]
TNfoTagsListValidator = ListValidator[TStringFormatterValidator]
class SharedNfoTagsValidator(DictValidator, ABC):
_tags_validator: Type[TNfoTagsListValidator]
_tags_with_attributes_validator: Type[TNfoTagsWithAttributesListValidator]
class NfoTagsValidator(DictValidator, ABC):
def __init__(self, name, value):
super().__init__(name, value)
self._string_tags: Dict[str, List[TStringFormatterValidator]] = defaultdict(list)
self._attribute_tags: Dict[str, List[TNfoTagsWithAttributesValidator]] = defaultdict(list)
self._string_tags: Dict[str, List[StringFormatterValidator]] = defaultdict(list)
self._attribute_tags: Dict[str, List[NfoTagsWithAttributesValidator]] = defaultdict(list)
for key, tag_value in self._dict.items():
# Turn each value into a list if it's not
@ -118,12 +61,12 @@ class SharedNfoTagsValidator(DictValidator, ABC):
self._string_tags[key].extend(
self._validate_key(
key=key,
validator=self._tags_validator,
validator=ListFormatterValidator,
).list
)
elif isinstance(tag_value[0], dict):
self._attribute_tags[key].extend(
self._validate_key(key=key, validator=self._tags_with_attributes_validator).list
self._validate_key(key=key, validator=NfoTagsWithAttributesListValidator).list
)
else:
raise self._validation_exception(
@ -131,7 +74,7 @@ class SharedNfoTagsValidator(DictValidator, ABC):
)
@property
def string_tags(self) -> Dict[str, List[TStringFormatterValidator]]:
def string_tags(self) -> Dict[str, List[StringFormatterValidator]]:
"""
Returns
-------
@ -140,20 +83,10 @@ class SharedNfoTagsValidator(DictValidator, ABC):
return self._string_tags
@property
def attribute_tags(self) -> Dict[str, List[TNfoTagsWithAttributesValidator]]:
def attribute_tags(self) -> Dict[str, List[NfoTagsWithAttributesValidator]]:
"""
Returns
-------
Tags with attributes
"""
return self._attribute_tags
class NfoTagsValidator(SharedNfoTagsValidator):
_tags_validator = ListFormatterValidator
_tags_with_attributes_validator = NfoTagsWithAttributesListValidator
class NfoOverrideTagsValidator(SharedNfoTagsValidator):
_tags_validator = ListOverridesFormatterValidator
_tags_with_attributes_validator = NfoOverrideTagsWithAttributesListValidator