From 374021d027b1908b33892bbaf9ed624eadcc1a86 Mon Sep 17 00:00:00 2001 From: jbannon Date: Mon, 4 Apr 2022 23:03:24 +0000 Subject: [PATCH] Fix validators and output directory --- config.yaml | 44 +++++++++++-------- subscriptions.yaml | 19 +++++--- ytdl_subscribe/subscriptions/subscription.py | 21 ++++++--- .../base/string_formatter_validator.py | 4 +- .../base/string_select_validator.py | 4 +- .../metadata_options_validator.py | 8 ---- .../validators/config/preset_validator.py | 5 ++- .../config/subscription_validator.py | 6 +-- 8 files changed, 61 insertions(+), 50 deletions(-) diff --git a/config.yaml b/config.yaml index 4a686373..8b3fc337 100644 --- a/config.yaml +++ b/config.yaml @@ -8,17 +8,21 @@ presets: skip_premiere_tracks: True ytdl_options: format: 'bestaudio[ext=mp3]' - post_process: + output_options: file_name: "[{album_year}] {sanitized_album}/{track_number_padded} - {sanitized_title}.{ext}" - thumbnail_name: "[{album_year}] {sanitized_album}/folder.{thumbnail_ext}" - tagging: - artist: "{artist}" - albumartist: "{artist}" - title: "{title}" - album: "{album}" - tracknumber: "{track_number}" - year: "{album_year}" - genre: "{genre}" + convert_thumbnail: "jpeg" + thumbnail_name: "[{album_year}] {sanitized_album}/folder.jpeg" + metadata_options: + id3: + id3_version: "2.4" + tags: + artist: "{artist}" + albumartist: "{artist}" + title: "{title}" + album: "{album}" + tracknumber: "{track_number}" + year: "{album_year}" + genre: "{genre}" music_videos: youtube: @@ -26,14 +30,16 @@ presets: ytdl_options: format: 'best' ignoreerrors: True - post_process: + output_options: file_name: "{sanitized_artist} - {sanitized_title}.{ext}" - convert_thumbnail: "jpg" - thumbnail_name: "{sanitized_artist} - {sanitized_title}.jpg" - nfo_name: "{sanitized_artist} - {sanitized_title}.nfo" - nfo_root: "musicvideo" + convert_thumbnail: "jpeg" + thumbnail_name: "{sanitized_artist} - {sanitized_title}.jpeg" + metadata_options: nfo: - artist: "{artist}" - title: "{title}" - album: "Music Videos" - year: "{upload_year}" + nfo_name: "{sanitized_artist} - {sanitized_title}.nfo" + nfo_root: "musicvideo" + tags: + artist: "{artist}" + title: "{title}" + album: "Music Videos" + year: "{upload_year}" diff --git a/subscriptions.yaml b/subscriptions.yaml index 1da717f9..25802f5b 100644 --- a/subscriptions.yaml +++ b/subscriptions.yaml @@ -2,7 +2,8 @@ ALISON: preset: "soundcloud_with_id3_tags" soundcloud: username: alis_on - output_path: "/mnt/nas/Downloads/ytdl/music/ALISON" + output_options: + output_directory: "/tmp/ALISON" overrides: artist: "A.L.I.S.O.N." genre: "Synthwave / Electronic" @@ -11,7 +12,8 @@ delorra: preset: "soundcloud_with_id3_tags" soundcloud: username: delorra - output_path: "/mnt/nas/Downloads/ytdl/music/DeLorra" + output_options: + output_directory: "/tmp/DeLorra" overrides: artist: "DeLorra" genre: "Synthwave / Electronic" @@ -20,23 +22,26 @@ bl00dwave: preset: "soundcloud_with_id3_tags" soundcloud: username: bl00dwave - output_path: "/tmp/bl00dwave" + output_options: + output_directory: "/tmp/bl00dwave" overrides: artist: "bl00dwave" genre: "Synthwave / Electronic" tom_petty: + preset: "music_videos" youtube: playlist_id: PLoopXDarluPBnuxs4PTC55Sc_2ShAXC0i - preset: "music_videos" - output_path: "/tmp/Tom Petty" + output_options: + output_directory: "/tmp/Tom Petty" overrides: artist: "Tom Petty and the Heartbreakers" rammstein: + preset: "music_videos" youtube: playlist_id: "PLVTLbc6i-h_iuhdwUfuPDLFLXG2QQnz-x" - preset: "music_videos" - output_path: "/mnt/nas/Downloads/ytdl/music_videos/Rammstein" + output_options: + output_directory: "/tmp/Rammstein" overrides: artist: "Rammstein" diff --git a/ytdl_subscribe/subscriptions/subscription.py b/ytdl_subscribe/subscriptions/subscription.py index a1b5efe6..a21f7a4b 100644 --- a/ytdl_subscribe/subscriptions/subscription.py +++ b/ytdl_subscribe/subscriptions/subscription.py @@ -1,4 +1,5 @@ import os +from pathlib import Path from shutil import copyfile from typing import Type from typing import TypeVar @@ -129,38 +130,44 @@ class Subscription(object): relative_directory=self.config_options.working_directory.value ) - entry_destination_file_path = entry.apply_formatter( + output_directory = entry.apply_formatter( + format_string=self.output_options.output_directory.format_string, + overrides=self.overrides.dict + ) + output_file_name = entry.apply_formatter( format_string=self.output_options.file_name.format_string, overrides=self.overrides.dict, ) + entry_destination_file_path = Path(output_directory) / Path(output_file_name) os.makedirs(os.path.dirname(entry_destination_file_path), exist_ok=True) copyfile(entry_source_file_path, entry_destination_file_path) # Download the thumbnail if its present if self.output_options.thumbnail_name: - thumbnail_source_path = entry.thumbnail_path( + source_thumbnail_path = entry.thumbnail_path( relative_directory=self.config_options.working_directory.value ) - thumbnail_destination_path = entry.apply_formatter( + output_thumbnail_name = entry.apply_formatter( format_string=self.output_options.thumbnail_name.format_string, overrides=self.overrides.dict, ) + output_thumbnail_path = Path(output_directory) / Path(output_thumbnail_name) - os.makedirs(os.path.dirname(entry_destination_file_path), exist_ok=True) + os.makedirs(os.path.dirname(output_thumbnail_path), exist_ok=True) # If the thumbnail is to be converted, then save the converted thumbnail to the # output filepath if self.output_options.convert_thumbnail: - im = Image.open(thumbnail_source_path).convert("RGB") + im = Image.open(source_thumbnail_path).convert("RGB") im.save( - fp=thumbnail_destination_path, + fp=output_thumbnail_name, format=self.output_options.convert_thumbnail.value, ) # Otherwise, just copy the downloaded thumbnail else: - copyfile(thumbnail_source_path, thumbnail_destination_path) + copyfile(source_thumbnail_path, output_thumbnail_name) if self.metadata_options.nfo: self._post_process_nfo(entry) diff --git a/ytdl_subscribe/validators/base/string_formatter_validator.py b/ytdl_subscribe/validators/base/string_formatter_validator.py index e516a2d5..d82bafa6 100644 --- a/ytdl_subscribe/validators/base/string_formatter_validator.py +++ b/ytdl_subscribe/validators/base/string_formatter_validator.py @@ -54,8 +54,8 @@ class StringFormatterValidator(StringValidator): return format_variables - def __init__(self, name, format_string: str): - super().__init__(name=name, value=format_string) + def __init__(self, name, value: str): + super().__init__(name=name, value=value) self.format_variables = self.__validate_and_get_format_variables() @property diff --git a/ytdl_subscribe/validators/base/string_select_validator.py b/ytdl_subscribe/validators/base/string_select_validator.py index 0e2e1a32..fae23e30 100644 --- a/ytdl_subscribe/validators/base/string_select_validator.py +++ b/ytdl_subscribe/validators/base/string_select_validator.py @@ -13,8 +13,8 @@ class StringSelectValidator(StringValidator): select_values: Set[str] = set() - def __init__(self, name, format_string: str): - super().__init__(name=name, value=format_string) + def __init__(self, name, value: str): + super().__init__(name=name, value=value) if self.value not in self.select_values: raise self._validation_exception( 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 d699a7cf..b08eee39 100644 --- a/ytdl_subscribe/validators/config/metadata_options/metadata_options_validator.py +++ b/ytdl_subscribe/validators/config/metadata_options/metadata_options_validator.py @@ -16,11 +16,3 @@ class MetadataOptionsValidator(StrictDictValidator): self.id3 = self.validate_key_if_present(key="id3", validator=Id3Validator) self.nfo = self.validate_key_if_present(key="nfo", validator=NFOValidator) - - self.output_directory: StringFormatterValidator = self.validate_key( - key="output_directory", validator=StringFormatterValidator - ) - - self.file_name: StringFormatterValidator = self.validate_key( - key="file_name", validator=StringFormatterValidator - ) diff --git a/ytdl_subscribe/validators/config/preset_validator.py b/ytdl_subscribe/validators/config/preset_validator.py index 2bd2c191..92f14ecf 100644 --- a/ytdl_subscribe/validators/config/preset_validator.py +++ b/ytdl_subscribe/validators/config/preset_validator.py @@ -38,7 +38,7 @@ class OverridesValidator(DictFormatterValidator): def dict(self) -> dict: """For overrides, create sanitized versions of each entry for convenience""" output_dict = copy.deepcopy(super().dict) - for key in self.keys: + for key in list(output_dict.keys()): output_dict[f"sanitized_{key}"] = sanitize_filename.sanitize( output_dict[key] ) @@ -47,8 +47,9 @@ class OverridesValidator(DictFormatterValidator): class PresetValidator(StrictDictValidator): - required_keys = {"output_options, metadata_options"} + required_keys = {"output_options"} optional_keys = { + "metadata_options", "ytdl_options", "overrides", *SubscriptionSourceName.all(), diff --git a/ytdl_subscribe/validators/config/subscription_validator.py b/ytdl_subscribe/validators/config/subscription_validator.py index 06ce4e1b..ec55cea6 100644 --- a/ytdl_subscribe/validators/config/subscription_validator.py +++ b/ytdl_subscribe/validators/config/subscription_validator.py @@ -17,7 +17,7 @@ from ytdl_subscribe.validators.config.config_validator import ConfigValidator from ytdl_subscribe.validators.config.preset_validator import OverridesValidator from ytdl_subscribe.validators.config.preset_validator import PresetValidator from ytdl_subscribe.validators.config.sources.soundcloud_validators import ( - SoundcloudSourceValidator, + SoundcloudSourceValidator, SoundcloudAlbumsAndSinglesDownloadValidator, ) from ytdl_subscribe.validators.config.sources.youtube_validators import ( YoutubePlaylistDownloadValidator, @@ -64,14 +64,14 @@ class SubscriptionValidator(StrictDictValidator): del preset_dict["preset"] self.preset = PresetValidator( - name=self.name, + name=f"{self.name}.{preset_name}", value=preset_dict, ) def to_subscription(self) -> Subscription: if isinstance( self.preset.subscription_source.download_strategy, - SoundcloudAlbumsAndSinglesSubscription, + SoundcloudAlbumsAndSinglesDownloadValidator, ): subscription_class = SoundcloudAlbumsAndSinglesSubscription elif isinstance(