Everything passing besides channel
This commit is contained in:
parent
30ad9501e6
commit
d89cb1c177
9 changed files with 96 additions and 13 deletions
|
|
@ -43,9 +43,9 @@ presets:
|
|||
# store previously downloaded song IDs to tell YTDL not to re-download
|
||||
# them on a successive invocation.
|
||||
output_options:
|
||||
output_directory: "/{music_directory}/{artist_sanitized}"
|
||||
file_name: "{album_directory_name}/{track_number_padded} - {title_sanitized}.{ext}"
|
||||
thumbnail_name: "{album_directory_name}/folder.jpg"
|
||||
output_directory: "{music_directory}"
|
||||
file_name: "{artist_sanitized}/{album_directory_name}/{track_number_padded} - {title_sanitized}.{ext}"
|
||||
thumbnail_name: "{artist_sanitized}/{album_directory_name}/folder.jpg"
|
||||
maintain_download_archive: True
|
||||
|
||||
# For each song downloaded, populate the audio file with music tags.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
from typing import Dict
|
||||
|
||||
import mediafile
|
||||
|
||||
from ytdl_sub.entries.entry import Entry
|
||||
from ytdl_sub.plugins.plugin import Plugin
|
||||
from ytdl_sub.plugins.plugin import PluginOptions
|
||||
from ytdl_sub.utils.file_handler import FileMetadata
|
||||
from ytdl_sub.validators.string_formatter_validators import DictFormatterValidator
|
||||
from ytdl_sub.validators.validators import StringValidator
|
||||
|
||||
|
|
@ -57,17 +60,28 @@ class MusicTagsPlugin(Plugin[MusicTagsOptions]):
|
|||
"""
|
||||
Tags the entry's audio file using values defined in the metadata options
|
||||
"""
|
||||
audio_file = mediafile.MediaFile(entry.get_download_file_path())
|
||||
for tag, tag_formatter in self.plugin_options.tags.dict.items():
|
||||
if tag not in audio_file.fields():
|
||||
supported_fields = list(mediafile.MediaFile.sorted_fields())
|
||||
tags_to_write: Dict[str, str] = {}
|
||||
for tag_name, tag_formatter in self.plugin_options.tags.dict.items():
|
||||
if tag_name not in supported_fields:
|
||||
# TODO: Add support for custom fields
|
||||
self._logger.warning(
|
||||
"tag '%s' is not supported for %s files. Supported tags: %s",
|
||||
tag,
|
||||
tag_name,
|
||||
entry.ext,
|
||||
", ".join(audio_file.sorted_fields()),
|
||||
", ".join(sorted(supported_fields)),
|
||||
)
|
||||
continue
|
||||
|
||||
tag_value = self.overrides.apply_formatter(formatter=tag_formatter, entry=entry)
|
||||
setattr(audio_file, tag, tag_value)
|
||||
tags_to_write[tag_name] = tag_value
|
||||
|
||||
audio_file.save()
|
||||
# write the actual tags if its not a dry run
|
||||
if not self.is_dry_run:
|
||||
audio_file = mediafile.MediaFile(entry.get_download_file_path())
|
||||
for tag_name, tag_value in tags_to_write.items():
|
||||
setattr(audio_file, tag_name, tag_value)
|
||||
audio_file.save()
|
||||
|
||||
# report the tags written
|
||||
return FileMetadata.from_dict(value_dict=tags_to_write, title="Music Tags:")
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import dicttoxml
|
|||
from ytdl_sub.entries.entry import Entry
|
||||
from ytdl_sub.plugins.plugin import Plugin
|
||||
from ytdl_sub.plugins.plugin import PluginOptions
|
||||
from ytdl_sub.utils.file_handler import FileMetadata
|
||||
from ytdl_sub.validators.string_formatter_validators import DictFormatterValidator
|
||||
from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator
|
||||
|
||||
|
|
@ -116,3 +117,5 @@ class NfoTagsPlugin(Plugin[NfoTagsOptions]):
|
|||
|
||||
# Archive the nfo's file name
|
||||
self.save_file(file_name=nfo_file_name, entry=entry)
|
||||
|
||||
return FileMetadata.from_dict(value_dict={nfo_root: nfo}, title="NFO tags:")
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import dicttoxml
|
|||
|
||||
from ytdl_sub.plugins.plugin import Plugin
|
||||
from ytdl_sub.plugins.plugin import PluginOptions
|
||||
from ytdl_sub.utils.file_handler import FileMetadata
|
||||
from ytdl_sub.validators.string_formatter_validators import OverridesDictFormatterValidator
|
||||
from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator
|
||||
|
||||
|
|
@ -106,3 +107,4 @@ class OutputDirectoryNfoTagsPlugin(Plugin[OutputDirectoryNfoTagsOptions]):
|
|||
nfo_file.write(xml)
|
||||
|
||||
self.save_file(file_name=nfo_file_name)
|
||||
return FileMetadata.from_dict(value_dict={nfo_root: nfo}, title="NFO tags:")
|
||||
|
|
|
|||
|
|
@ -46,6 +46,14 @@ class Plugin(Generic[PluginOptionsT], ABC):
|
|||
def working_directory(self) -> str:
|
||||
return self.__enhanced_download_archive.working_directory
|
||||
|
||||
@property
|
||||
def output_directory(self) -> str:
|
||||
return self.__enhanced_download_archive.output_directory
|
||||
|
||||
@property
|
||||
def is_dry_run(self) -> bool:
|
||||
return self.__enhanced_download_archive.is_dry_run
|
||||
|
||||
def save_file(self, file_name: str, entry: Optional[Entry] = None) -> None:
|
||||
"""
|
||||
Saves a file in the working directory to the output directory.
|
||||
|
|
|
|||
|
|
@ -12,10 +12,31 @@ class FileMetadata:
|
|||
def __init__(self, metadata: Optional[List[str]] = None):
|
||||
self.metadata: List[str] = metadata if metadata else []
|
||||
|
||||
def append(self, other: "FileMetadata") -> "FileMetadata":
|
||||
def append(self, line: str) -> "FileMetadata":
|
||||
self.metadata.append(line)
|
||||
return self
|
||||
|
||||
def extend(self, other: "FileMetadata") -> "FileMetadata":
|
||||
self.metadata.extend(other.metadata)
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, value_dict: Dict[str, str], title: Optional[str] = None) -> "FileMetadata":
|
||||
lines: List[str] = []
|
||||
if title is not None:
|
||||
lines.append(title)
|
||||
|
||||
def _recursive_add_dict_lines(rdict: Dict, indent: int):
|
||||
for key, value in sorted(rdict.items()):
|
||||
if isinstance(value, Dict):
|
||||
_recursive_add_dict_lines(rdict=value, indent=indent + 2)
|
||||
|
||||
_indent = " " * indent
|
||||
lines.append(f"{_indent}{key}: {value}")
|
||||
|
||||
_recursive_add_dict_lines(rdict=value_dict, indent=2)
|
||||
return cls(metadata=lines)
|
||||
|
||||
|
||||
class FileHandlerTransactionLog:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -373,6 +373,10 @@ class EnhancedDownloadArchive:
|
|||
self._download_mapping = DownloadMappings()
|
||||
return self
|
||||
|
||||
@property
|
||||
def is_dry_run(self) -> bool:
|
||||
return self._file_handler.dry_run
|
||||
|
||||
@property
|
||||
def archive_file_name(self) -> str:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ def subscription_dict(output_directory, subscription_name):
|
|||
"preset": "sc_discography",
|
||||
"soundcloud": {"url": "https://soundcloud.com/jessebannon"},
|
||||
# override the output directory with our fixture-generated dir
|
||||
"output_options": {"output_directory": output_directory + "/{artist_sanitized}"},
|
||||
"output_options": {"output_directory": output_directory},
|
||||
# download the worst format so it is fast
|
||||
"ytdl_options": {
|
||||
"format": "worst[ext=mp3]",
|
||||
|
|
@ -59,7 +59,7 @@ def expected_discography_download():
|
|||
return ExpectedDownload(
|
||||
expected_md5_file_hashes={
|
||||
# Download mapping
|
||||
Path("j_b/.ytdl-sub-jb-download-archive.json"): "ae55de93b71267b5712c9a3d06c07c26",
|
||||
Path(".ytdl-sub-jb-download-archive.json"): "1a99156e9ece62539fb2608416a07200",
|
||||
|
||||
# Entry files (singles)
|
||||
Path("j_b/[2021] Baby Santana's Dorian Groove/01 - Baby Santana's Dorian Groove.mp3"): "bffbd558e12c6a9e029dc136a88342c4",
|
||||
|
|
@ -99,3 +99,9 @@ class TestSoundcloudDiscography:
|
|||
):
|
||||
discography_subscription.download()
|
||||
expected_discography_download.assert_files_exist(relative_directory=output_directory)
|
||||
|
||||
def test_discography_dry_run(
|
||||
self, discography_subscription, expected_discography_download, output_directory
|
||||
):
|
||||
transaction_log = discography_subscription.download(dry_run=True)
|
||||
expected_discography_download.assert_dry_run_files_logged(transaction_log=transaction_log)
|
||||
|
|
|
|||
|
|
@ -297,6 +297,12 @@ class TestChannelAsKodiTvShow:
|
|||
full_channel_subscription.download()
|
||||
expected_full_channel_download.assert_files_exist(relative_directory=output_directory)
|
||||
|
||||
def test_full_channel_dry_run(
|
||||
self, full_channel_subscription, expected_full_channel_download, output_directory
|
||||
):
|
||||
transaction_log = full_channel_subscription.download(dry_run=True)
|
||||
expected_full_channel_download.assert_dry_run_files_logged(transaction_log=transaction_log)
|
||||
|
||||
def test_recent_channel_download(
|
||||
self, recent_channel_subscription, expected_recent_channel_download, output_directory
|
||||
):
|
||||
|
|
@ -311,6 +317,14 @@ class TestChannelAsKodiTvShow:
|
|||
recent_channel_subscription.download()
|
||||
expected_recent_channel_download.assert_files_exist(relative_directory=output_directory)
|
||||
|
||||
def test_recent_channel_dry_run(
|
||||
self, recent_channel_subscription, expected_recent_channel_download, output_directory
|
||||
):
|
||||
transaction_log = recent_channel_subscription.download(dry_run=True)
|
||||
expected_recent_channel_download.assert_dry_run_files_logged(
|
||||
transaction_log=transaction_log
|
||||
)
|
||||
|
||||
def test_recent_channel_download__no_vids_in_range(
|
||||
self,
|
||||
recent_channel_no_vids_in_range_subscription,
|
||||
|
|
@ -328,6 +342,17 @@ class TestChannelAsKodiTvShow:
|
|||
relative_directory=output_directory
|
||||
)
|
||||
|
||||
def test_recent_channel_dry_run__no_vids_in_range(
|
||||
self,
|
||||
recent_channel_no_vids_in_range_subscription,
|
||||
expected_recent_channel_no_vids_in_range_download,
|
||||
output_directory,
|
||||
):
|
||||
transaction_log = recent_channel_no_vids_in_range_subscription.download(dry_run=True)
|
||||
expected_recent_channel_no_vids_in_range_download.assert_dry_run_files_logged(
|
||||
transaction_log=transaction_log
|
||||
)
|
||||
|
||||
def test_rolling_recent_channel_download(
|
||||
self,
|
||||
recent_channel_subscription,
|
||||
|
|
|
|||
Loading…
Reference in a new issue