diff --git a/examples/music_video_subscriptions.yaml b/examples/music_video_subscriptions.yaml index 26cb1385..9f0fddb9 100644 --- a/examples/music_video_subscriptions.yaml +++ b/examples/music_video_subscriptions.yaml @@ -24,3 +24,13 @@ __preset__: "Michael Jackson": "https://www.youtube.com/playlist?list=OLAK5uy_mnY03zP6abNWH929q2XhGzWD_2uKJ_n8E" = Blues: "Eric Clapton": "https://www.youtube.com/playlist?list=PLABGggHhsbEeaRtdzqnxYoEINsJE_4GF4" + + = Rock: + # TODO: DOCUMENTATION + "+ Guns N' Roses": + Music Videos: + - "https://www.youtube.com/playlist?list=PLOTK54q5K4INNXaHKtmXYr6J7CajWjqeJ" + Concerts: + - title: "Live at The Ritz - New York City" + date: "1988" + url: "https://www.youtube.com/watch?v=OldpIhHPsbs" \ No newline at end of file diff --git a/src/ytdl_sub/entries/variables/override_variables.py b/src/ytdl_sub/entries/variables/override_variables.py index 68ec72d4..42bb4498 100644 --- a/src/ytdl_sub/entries/variables/override_variables.py +++ b/src/ytdl_sub/entries/variables/override_variables.py @@ -3,6 +3,7 @@ from typing import Set from ytdl_sub.entries.script.function_scripts import CUSTOM_FUNCTION_SCRIPTS from ytdl_sub.entries.script.variable_definitions import VARIABLE_SCRIPTS +from ytdl_sub.entries.script.variable_types import ArrayVariable from ytdl_sub.entries.script.variable_types import BooleanVariable from ytdl_sub.entries.script.variable_types import MapVariable from ytdl_sub.entries.script.variable_types import StringVariable @@ -36,6 +37,21 @@ class SubscriptionVariables: """ return StringVariable(variable_name="subscription_value", definition="{ %string('') }") + @staticmethod + def subscription_array() -> ArrayVariable: + """ + For subscriptions in the form of + + .. code-block:: yaml + + "Subscription Name": + - "https://url1.com/..." + - "https://url2.com/..." + + Store all values into an array named ``subscription_array``. + """ + return ArrayVariable(variable_name="subscription_array", definition="{ [] }") + @staticmethod def subscription_indent_i(index: int) -> StringVariable: """ diff --git a/src/ytdl_sub/prebuilt_presets/helpers/url.yaml b/src/ytdl_sub/prebuilt_presets/helpers/url.yaml index 3a9726dd..7fc1d9ad 100644 --- a/src/ytdl_sub/prebuilt_presets/helpers/url.yaml +++ b/src/ytdl_sub/prebuilt_presets/helpers/url.yaml @@ -129,6 +129,7 @@ presets: avatar_uncropped_thumbnail_file_name: "" banner_uncropped_thumbnail_file_name: "" + subscription_array: "{ [] }" subscription_value: "" subscription_value_2: "" subscription_value_3: "" diff --git a/src/ytdl_sub/prebuilt_presets/helpers/url_categorized.yaml b/src/ytdl_sub/prebuilt_presets/helpers/url_categorized.yaml index d9652853..b212f640 100644 --- a/src/ytdl_sub/prebuilt_presets/helpers/url_categorized.yaml +++ b/src/ytdl_sub/prebuilt_presets/helpers/url_categorized.yaml @@ -64,7 +64,7 @@ presets: # Creates an array in the form of [ { url: ..., category: ..., metadata_field_1: ... }, ... ] category_url_array: >- - { %array_flatten( %map_apply( subscription_dict, %flat_array__category_to_map_format ) ) } + { %array_flatten( %map_apply( subscription_map, %flat_array__category_to_map_format ) ) } # Creates a map in the form of { : { category: ..., metadata_field_1: ... }, ... } category_url_map: >- @@ -82,8 +82,16 @@ presets: # Output: # Metadata field value if it exists. Otherwise, return default value "%get_url_field": >- - { - %map_get( %map( %map_get( category_url_map, ytdl_sub_input_url, {} ) ), $0, $1 ) } + { %map_get( %map( %map_get( category_url_map, ytdl_sub_input_url, {} ) ), $0, $1 ) } + + # Parameters: + # $0: metadata field to fetch for the current url + # + # Output: + # True if field is specified. False otherwise. + "%contains_url_field": >- + { %not( %is_null( %get_url_field( $0, null ) ) ) } + # Parameters: # $0: integer to fetch the i'th url using 1-based indexing @@ -91,8 +99,15 @@ presets: # Output: # i'th url in the category map "%get_url_i": >- - { %map_get( %map( %array_at( category_url_array, %int( %sub($0, 1) ), {} ) ), "url", null )} + { + %map_get( + %map( %array_at( category_url_array, %int( %sub($0, 1) ), {} ) ), + "url", + %array_at(subscription_array, %int( %sub($0, 1) ), null) + ) + } + subscription_map: "{ {} }" url: "{ %get_url_i(1) }" url2: "{ %get_url_i(2) }" url3: "{ %get_url_i(3) }" diff --git a/src/ytdl_sub/prebuilt_presets/music_videos/music_video_base.yaml b/src/ytdl_sub/prebuilt_presets/music_videos/music_video_base.yaml index 338e3a25..25b97697 100644 --- a/src/ytdl_sub/prebuilt_presets/music_videos/music_video_base.yaml +++ b/src/ytdl_sub/prebuilt_presets/music_videos/music_video_base.yaml @@ -21,7 +21,6 @@ presets: # Defaults music_video_genre_default: "ytdl-sub" music_video_album_default: "Music Videos" - subscription_dict: "{ {} }" # Subscription overrides subscription_indent_1: "{music_video_genre_default}" @@ -34,9 +33,29 @@ presets: music_video_title: >- { %get_url_field("title", title) } music_video_date: >- - { %get_url_field("date", upload_date_standardized) } + { + %elif( + %contains_url_field("date"), + %get_url_field("date", upload_date_standardized), + + %contains_url_field("year"), + %concat( %get_url_field("date", upload_year), "-01-01"), + + upload_date_standardized + ) + } music_video_year: >- - { %int( %slice( music_video_date, 0, 4 ) ) } + { + %int(%elif( + %contains_url_field("date"), + %slice( %get_url_field("date", upload_date_standardized), 0, 4 ), + + %contains_url_field("year"), + %get_url_field("date", upload_year), + + upload_year + )) + } # Directory Overrides diff --git a/src/ytdl_sub/subscriptions/subscription_validators.py b/src/ytdl_sub/subscriptions/subscription_validators.py index 5994c218..35bbbcb7 100644 --- a/src/ytdl_sub/subscriptions/subscription_validators.py +++ b/src/ytdl_sub/subscriptions/subscription_validators.py @@ -143,10 +143,21 @@ class SubscriptionValueValidator(SubscriptionLeafValidator, StringValidator): presets=presets, indent_overrides=indent_overrides, ) + # subscription_value self._overrides_to_add[SubscriptionVariables.subscription_value().variable_name] = ( self.value ) + # subscription_value_0 + self._overrides_to_add[ + SubscriptionVariables.subscription_value_i(index=0).variable_name + ] = self.value + + # And the array variable + self._overrides_to_add[SubscriptionVariables.subscription_array().variable_name] = ( + ScriptUtils.to_script([self.value]) + ) + class SubscriptionListValuesValidator(SubscriptionLeafValidator, StringListValidator): def __init__( @@ -167,6 +178,7 @@ class SubscriptionListValuesValidator(SubscriptionLeafValidator, StringListValid indent_overrides=indent_overrides, ) + # Add indexed variables for idx, list_value in enumerate(self.list): # Write the first list value into subscription_value as well if idx == 0: @@ -178,6 +190,11 @@ class SubscriptionListValuesValidator(SubscriptionLeafValidator, StringListValid SubscriptionVariables.subscription_value_i(index=idx).variable_name ] = list_value.value + # And the array variable + self._overrides_to_add[SubscriptionVariables.subscription_array().variable_name] = ( + ScriptUtils.to_script([list_value.value for list_value in self.list]) + ) + class SubscriptionWithOverridesValidator(SubscriptionLeafValidator, DictFormatterValidator): def __init__( @@ -220,7 +237,7 @@ class SubscriptionMapValidator(SubscriptionLeafValidator, LiteralDictValidator): indent_overrides=indent_overrides, ) self._overrides_to_add[SubscriptionVariables.subscription_map().variable_name] = ( - ScriptUtils.to_script(self.dict) + ScriptUtils.to_script(self.dict, sort_keys=False) ) diff --git a/src/ytdl_sub/utils/script.py b/src/ytdl_sub/utils/script.py index fba88a35..e3a17b2f 100644 --- a/src/ytdl_sub/utils/script.py +++ b/src/ytdl_sub/utils/script.py @@ -35,7 +35,7 @@ class ScriptUtils: return dict(variables, **sanitized_variables) @classmethod - def to_script(cls, value: Any) -> str: + def to_script(cls, value: Any, sort_keys: bool = True) -> str: """ Converts a python value to a script value """ @@ -50,7 +50,7 @@ class ScriptUtils: elif isinstance(value, float): out = f"{{%float({value})}}" else: - dumped_json = json.dumps(value, ensure_ascii=False, sort_keys=True) + dumped_json = json.dumps(value, ensure_ascii=False, sort_keys=sort_keys) # Remove triple-single-quotes from JSON to avoid parsing issues dumped_json = re.sub("'{3,}", "'", dumped_json) diff --git a/tests/unit/config/test_subscription.py b/tests/unit/config/test_subscription.py index e01525b7..45b60928 100644 --- a/tests/unit/config/test_subscription.py +++ b/tests/unit/config/test_subscription.py @@ -493,16 +493,31 @@ def test_music_video_subscriptions(default_config: ConfigFile, music_video_subsc config=default_config, subscription_path=music_video_subscription_path ) - assert len(subs) == 3 + assert len(subs) == 4 assert subs[1].name == "Michael Jackson" - monk = subs[1].overrides.script + jackson = subs[1].overrides.script - assert monk.get("subscription_name").native == "Michael Jackson" + assert jackson.get("subscription_name").native == "Michael Jackson" assert ( - monk.get("subscription_value").native + jackson.get("subscription_value").native == "https://www.youtube.com/playlist?list=OLAK5uy_mnY03zP6abNWH929q2XhGzWD_2uKJ_n8E" ) - assert monk.get("subscription_indent_1").native == "Pop" + assert jackson.get("subscription_indent_1").native == "Pop" + assert ( + jackson.get("url").native + == "https://www.youtube.com/playlist?list=OLAK5uy_mnY03zP6abNWH929q2XhGzWD_2uKJ_n8E" + ) + + assert subs[3].name == "Guns N' Roses" + gnr = subs[3].overrides.script + + assert gnr.get("subscription_name").native == "Guns N' Roses" + assert ( + gnr.get("url").native + == "https://www.youtube.com/playlist?list=PLOTK54q5K4INNXaHKtmXYr6J7CajWjqeJ" + ) + assert gnr.get("subscription_indent_1").native == "Rock" + assert gnr.get("url2").native == "https://www.youtube.com/watch?v=OldpIhHPsbs" def test_default_docker_config_and_subscriptions():