use yaml for print

This commit is contained in:
Jesse Bannon 2022-09-07 10:51:25 -07:00
parent 56bae3f39a
commit 68f2e768e7
13 changed files with 213 additions and 104 deletions

View file

@ -122,7 +122,7 @@ class YoutubeMergePlaylistDownloader(
file_duration_sec=merged_video.kwargs("duration"),
)
return chapters.to_file_metadata(title="Timestamps of playlist videos in the merged file:")
return chapters.to_file_metadata(title="Timestamps of playlist videos in the merged file")
def _to_merged_video(self, entry_dict: Dict) -> YoutubeVideo:
"""

View file

@ -334,7 +334,7 @@ class ChaptersPlugin(Plugin[ChaptersOptions]):
chapters = Chapters.from_timestamps_file(
chapters_file_path=self.plugin_options.embed_chapter_timestamps
)
return chapters.to_file_metadata(title="Chapters embedded from timestamp file:")
return chapters.to_file_metadata(title="Chapters embedded from timestamp file")
if self.plugin_options.embed_chapters:
metadata_dict = {}

View file

@ -84,4 +84,4 @@ class MusicTagsPlugin(Plugin[MusicTagsOptions]):
audio_file.save()
# report the tags written
return FileMetadata.from_dict(value_dict=tags_to_write, title="Music Tags:")
return FileMetadata.from_dict(value_dict=tags_to_write, title="Music Tags")

View file

@ -1,5 +1,6 @@
import os
from abc import ABC
from collections import defaultdict
from pathlib import Path
from typing import Dict
from typing import Generic
@ -97,19 +98,19 @@ class SharedNfoTagsPlugin(
"""
def _get_xml_element_dict(self, entry: Optional[Entry]) -> Dict[str, List[XmlElement]]:
nfo_tags: Dict[str, List[XmlElement]] = {}
nfo_tags: Dict[str, List[XmlElement]] = defaultdict(list)
for key, string_tags in self.plugin_options.tags.string_tags.items():
nfo_tags[key] = [
nfo_tags[key].extend(
XmlElement(
text=self.overrides.apply_formatter(formatter=string_tag, entry=entry),
attributes={},
)
for string_tag in string_tags
]
)
for key, attribute_tags in self.plugin_options.tags.attribute_tags.items():
nfo_tags[key] = [
nfo_tags[key].extend(
XmlElement(
text=self.overrides.apply_formatter(formatter=attribute_tag.tag, entry=entry),
attributes={
@ -120,7 +121,7 @@ class SharedNfoTagsPlugin(
},
)
for attribute_tag in attribute_tags
]
)
return nfo_tags
@ -168,7 +169,7 @@ class SharedNfoTagsPlugin(
for key, xml_elems in nfo_tags.items()
}
},
title="NFO tags:",
title="NFO tags",
)
self.save_file(file_name=nfo_file_name, file_metadata=nfo_metadata, entry=entry)

View file

@ -136,7 +136,7 @@ class SplitByChaptersPlugin(Plugin[SplitByChaptersOptions]):
metadata = FileMetadata.from_dict(
value_dict=metadata_value_dict,
title="From Chapter Split:",
title="From Chapter Split",
sort_dict=False,
)

View file

@ -59,4 +59,4 @@ class VideoTagsPlugin(Plugin[VideoTagsOptions]):
)
# report the tags written
return FileMetadata.from_dict(value_dict=tags_to_write, title="Video Tags:")
return FileMetadata.from_dict(value_dict=tags_to_write, title="Video Tags")

View file

@ -1,3 +1,4 @@
import json
import os
import shutil
from pathlib import Path
@ -7,6 +8,7 @@ from typing import List
from typing import Optional
from typing import Set
from typing import Union
import yaml
class FileMetadata:
@ -56,32 +58,13 @@ class FileMetadata:
sort_dict
Whether to sort dicts in the value_dict. Defaults to true.
"""
lines: List[str] = []
if title is not None:
lines.append(title)
if title:
value_dict = {title: value_dict}
if sort_dict:
value_dict = json.loads(json.dumps(value_dict, sort_keys=True))
def _recursive_add_dict_lines(rdict: Dict, indent: int):
rdict_items = rdict.items()
if sort_dict:
rdict_items = sorted(rdict_items)
for key, value in rdict_items:
_indent = " " * indent
if isinstance(value, Dict):
lines.append(f"{_indent}{key}:")
_recursive_add_dict_lines(rdict=value, indent=indent + 2)
else:
value = str(value)
# If there are newlines in the value, print them indented
if "\n" in value:
lines.append(f"{_indent}{key}:")
for value_line in value.split("\n"):
lines.append(f" {_indent}{value_line.strip()}")
else:
lines.append(f"{_indent}{key}: {value}")
_recursive_add_dict_lines(rdict=value_dict, indent=2)
return cls(metadata=lines)
out = yaml.safe_dump(value_dict, allow_unicode=True, indent=2, default_style='', width=100)
return cls(metadata=out.rstrip().split('\n'))
class FileHandlerTransactionLog:

View file

@ -1,6 +1,6 @@
import xml.etree.ElementTree as et
from dataclasses import dataclass
from typing import Any
from typing import Any, List
from typing import Dict
from typing import Union
@ -59,7 +59,7 @@ def to_max_3_byte_utf8_dict(string_dict: Dict[str, str]) -> Dict[str, str]:
}
def to_xml(nfo_dict: Dict[str, XmlElement], nfo_root: str) -> bytes:
def to_xml(nfo_dict: Dict[str, List[XmlElement]], nfo_root: str) -> bytes:
"""
Transforms a dict to XML
@ -75,10 +75,11 @@ def to_xml(nfo_dict: Dict[str, XmlElement], nfo_root: str) -> bytes:
XML bytes
"""
xml_root = et.Element(nfo_root)
for key, xml_elem in sorted(nfo_dict.items()):
sorted_attr = dict(sorted(xml_elem.attributes.items()))
sub_element = et.SubElement(xml_root, key, sorted_attr)
sub_element.text = xml_elem.text
for key, xml_elems in sorted(nfo_dict.items()):
for xml_elem in xml_elems:
sorted_attr = dict(sorted(xml_elem.attributes.items()))
sub_element = et.SubElement(xml_root, key, sorted_attr)
sub_element.text = xml_elem.text
et.indent(tree=xml_root, space=" ", level=0)
return et.tostring(element=xml_root, encoding="utf-8", xml_declaration=True)

View file

@ -7,11 +7,13 @@ 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 DictFormatterValidator, \
ListFormatterValidator, 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)
@ -55,34 +57,54 @@ class _NfoTagsWithAttributesValidator(
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
TNfoTagsWithAttributesValidator = _NfoTagsWithAttributesValidator[
TStringFormatterValidator, TDictFormatterValidator
]
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, Generic[TStringFormatterValidator, TDictFormatterValidator], ABC
DictValidator, ABC
):
_tags_with_attributes_validator: Type[TNfoTagsWithAttributesValidator]
_tags_validator: Type[TNfoTagsListValidator]
_tags_with_attributes_validator: Type[TNfoTagsWithAttributesListValidator]
def __init__(self, name, value):
super().__init__(name, value)
self._string_tags: Dict[str, List[StringFormatterValidator]] = defaultdict(list)
self._string_tags: Dict[str, List[TStringFormatterValidator]] = defaultdict(list)
self._attribute_tags: Dict[str, List[TNfoTagsWithAttributesValidator]] = defaultdict(list)
for key, tag_value in self._dict.items():
@ -93,15 +115,17 @@ class SharedNfoTagsValidator(
# iterate each list, validate accordingly if it is a string tag or attribute tag
for tag_value_i in tag_value:
if isinstance(tag_value_i, str):
self._string_tags[key].append(
self._string_tags[key].extend(
self._validate_key(
key=key,
validator=self._tags_with_attributes_validator.formatter_validator,
)
validator=self._tags_validator,
).list
)
elif isinstance(tag_value_i, dict):
self._attribute_tags[key].append(
self._validate_key(key=key, validator=self._tags_with_attributes_validator)
self._attribute_tags[key].extend(
self._validate_key(
key=key, validator=self._tags_with_attributes_validator
).list
)
else:
raise self._validation_exception(
@ -109,7 +133,7 @@ class SharedNfoTagsValidator(
)
@property
def string_tags(self) -> Dict[str, List[StringFormatterValidator]]:
def string_tags(self) -> Dict[str, List[TStringFormatterValidator]]:
"""
Returns
-------
@ -127,11 +151,11 @@ class SharedNfoTagsValidator(
return self._attribute_tags
class NfoTagsValidator(SharedNfoTagsValidator[StringFormatterValidator, DictFormatterValidator]):
_tags_with_attributes_validator = NfoTagsWithAttributesValidator
class NfoTagsValidator(SharedNfoTagsValidator):
_tags_validator = ListFormatterValidator
_tags_with_attributes_validator = NfoTagsWithAttributesListValidator
class NfoOverrideTagsValidator(
SharedNfoTagsValidator[OverridesStringFormatterValidator, OverridesDictFormatterValidator]
):
_tags_with_attributes_validator = NfoOverrideTagsWithAttributesValidator
class NfoOverrideTagsValidator(SharedNfoTagsValidator):
_tags_validator = ListOverridesFormatterValidator
_tags_with_attributes_validator = NfoOverrideTagsWithAttributesListValidator

View file

@ -209,6 +209,9 @@ class ListFormatterValidator(ListValidator[StringFormatterValidator]):
_inner_list_type = StringFormatterValidator
class ListOverridesFormatterValidator(ListValidator[StringFormatterValidator]):
_inner_list_type = OverridesStringFormatterValidator
class DictFormatterValidator(LiteralDictValidator):
"""
A dict made up of
@ -241,4 +244,3 @@ class OverridesDictFormatterValidator(DictFormatterValidator):
"""
_key_validator = OverridesStringFormatterValidator

View file

@ -33,7 +33,7 @@ def subscription_dict(output_directory):
"attributes": {"🎸?": "value\nnewlines 🎸"},
"tag": "the \n tag 2 🎸🎸",
},
]
],
},
},
"output_directory_nfo_tags": {
@ -55,7 +55,7 @@ def subscription_dict(output_directory):
"attributes": {"🎸?": "value\nnewlines 🎸"},
"tag": "the \n tag 2 🎸🎸",
},
]
],
},
},
}
@ -82,7 +82,7 @@ class TestNfoTagsPlugins:
output_directory=output_directory,
transaction_log=transaction_log,
transaction_log_summary_file_name=f"plugins/nfo_tags/{transaction_log_file_name}",
regenerate_transaction_log=True
regenerate_transaction_log=True,
)
def test_source_variable_in_output_directory_nfo_tags_errors(

View file

@ -5,29 +5,79 @@ Rick Beato - Can you hear the difference 🎸🔥 #shorts.3gp
Rick Beato - Can you hear the difference 🎸🔥 #shorts.info.json
Rick Beato - Can you hear the difference 🎸🔥 #shorts.nfo
NFO tags:
musicvideo:
album: Music Videos
artist: Rick Beato
kodi_safe_title 🎸: kodi_safe_value 🎸
kodi_safe_title_with_attrs:
attributes:
🎸?:
value
newlines 🎸
tag:
the
tag 🎸🎸
title: Can you hear the difference? 🎸🔥 #shorts
year: 2022
album: Music Videos
artist: Rick Beato
- value 1 🎸
- value 2 🎸
- value 1 🎸
- value 2 🎸
🎸?:
value
newlines 🎸
tag:
the
tag 1 🎸🎸
🎸?:
value
newlines 🎸
tag:
the
tag 2 🎸🎸
🎸?:
value
newlines 🎸
tag:
the
tag 1 🎸🎸
🎸?:
value
newlines 🎸
tag:
the
tag 2 🎸🎸
kodi_safe_title 🎸: kodi_safe_value 🎸
🎸?:
value
newlines 🎸
tag:
the
tag 🎸🎸
title: Can you hear the difference? 🎸🔥 #shorts
year: 2022
test.nfo
NFO tags:
kodi_safe_root 🎸:
kodi_safe_title 🎸: kodi_safe_value 🎸
kodi_safe_title_with_attrs:
attributes:
🎸?:
value
newlines 🎸
tag:
the
tag 🎸🎸
- value 1 🎸
- value 2 🎸
- value 1 🎸
- value 2 🎸
🎸?:
value
newlines 🎸
tag:
the
tag 1 🎸🎸
🎸?:
value
newlines 🎸
tag:
the
tag 2 🎸🎸
🎸?:
value
newlines 🎸
tag:
the
tag 1 🎸🎸
🎸?:
value
newlines 🎸
tag:
the
tag 2 🎸🎸
kodi_safe_title 🎸: kodi_safe_value 🎸
🎸?:
value
newlines 🎸
tag:
the
tag 🎸🎸

View file

@ -8,26 +8,74 @@ Rick Beato - Can you hear the difference 🎸🔥 #shorts.nfo
musicvideo:
album: Music Videos
artist: Rick Beato
kodi_safe_multi_title □:
- value 1 □
- value 2 □
- value 1 □
- value 2 □
kodi_safe_multi_title_with_attrs:
- attributes:
□?: 'value
newlines □'
tag: "the \n tag 1 □□"
- attributes:
□?: 'value
newlines □'
tag: "the \n tag 2 □□"
- attributes:
□?: 'value
newlines □'
tag: "the \n tag 1 □□"
- attributes:
□?: 'value
newlines □'
tag: "the \n tag 2 □□"
kodi_safe_title □: kodi_safe_value □
kodi_safe_title_with_attrs:
attributes:
□?:
value
newlines □
tag:
the
tag □□
title: Can you hear the difference? □□ #shorts
year: 2022
□?: 'value
newlines □'
tag: "the \n tag □□"
title: 'Can you hear the difference? □□ #shorts'
year: '2022'
test.nfo
NFO tags:
kodi_safe_root □:
kodi_safe_multi_title □:
- value 1 □
- value 2 □
- value 1 □
- value 2 □
kodi_safe_multi_title_with_attrs:
- attributes:
□?: 'value
newlines □'
tag: "the \n tag 1 □□"
- attributes:
□?: 'value
newlines □'
tag: "the \n tag 2 □□"
- attributes:
□?: 'value
newlines □'
tag: "the \n tag 1 □□"
- attributes:
□?: 'value
newlines □'
tag: "the \n tag 2 □□"
kodi_safe_title □: kodi_safe_value □
kodi_safe_title_with_attrs:
attributes:
□?:
value
newlines □
tag:
the
tag □□
□?: 'value
newlines □'
tag: "the \n tag □□"