diff --git a/src/ytdl_sub/prebuilt_presets/helpers/keyed_url.yaml b/src/ytdl_sub/prebuilt_presets/helpers/keyed_url.yaml deleted file mode 100644 index bb8ebb0c..00000000 --- a/src/ytdl_sub/prebuilt_presets/helpers/keyed_url.yaml +++ /dev/null @@ -1,134 +0,0 @@ -# -# Kodi Music Videos with Extras: -# + Rick Astley: -# Music Videos: -# - url1 -# - url2 -# ... -# Concerts: -# - url: asfasdfasdf -# year: 2023 -# title: sdfasff -# exclude: asdffsdf -# - url4 -# Extras: -# - url5 -# - url6 -# Behind The Scenes: -# - ... -# Live: -# - ... -# Lyrics: -# - ... - -presets: - _keyed_url: - - overrides: - - # Takes a value and standardizes it to a dict, i.e. - # - # Concerts: - # - https://url1 -> { "url": "https://url1" } - # - url: https://url2 - # title: custom title -> { "url": "https://url2", "title": "custom title" } - "%standardize_value_to_dict": >- - { - %if( - %is_string($0), - { "url": $0 }, - $0 - ) - } - - # Takes a Subscription Dict in the form of - # - # Concerts: - # - https://url1 - # - url: https://url2 - # title: custom title - # Another: - # - https://url3 - # - # and standardizes it to - # - # [ - # { "key": "Concerts", "url": "https://url1" }, - # { "key": "Concerts", "url": "https://url2", "title": "custom title" }, - # { "key": "Another", "url": "https://url3" } - # ] - "%subscription_dict_to_list__inner": >- - { - %map_extend( - { "key": $0 }, - %assert_then( - %if( - %is_dict( %standardize_value_to_dict( $1 ) ), - %map_contains( %standardize_value_to_dict( $1 ), "url" ), - False - ), - %standardize_value_to_dict( $1 ), - "Value must be either a string or a Map with the key 'url'" - ) - ) - } - - # The actual variable that holds the subscription list of maps - subscription_map_list: >- - { - %map_apply( subscription_dict, %subscription_dict_to_list__inner ) - } - - # Helper function to get the i'th map in the subscription list. - # Returns an empty map if it does not exist. - "%get_subscription_map_i": >- - { - %array_at( subscription_map_list, $0, {} ) - } - - # Helper function to get the i'th map's url in the subscription list. - # Returns null if it does not exist. - "%get_subscription_map_i_url": >- - { - %map_get( - %get_subscription_map_i( $0 ), - "url", - null - ) - } - - - download: - - url: "{ %get_subscription_map_i_url(0) }" - playlist_thumbnails: - - name: "{avatar_uncropped_thumbnail_file_name}" - uid: "avatar_uncropped" - - name: "{banner_uncropped_thumbnail_file_name}" - uid: "banner_uncropped" - variables: - keyed_metadata: "{ %get_subscription_map_i(0) }" - - url: "{ %get_url_by_idx(1) }" - variables: - keyed_metadata: "{ %get_subscription_map_i(1) }" - - url: "{ %get_url_by_idx(2) }" - variables: - keyed_metadata: "{ %get_subscription_map_i(2) }" - - url: "{ %get_url_by_idx(3) }" - variables: - keyed_metadata: "{ %get_subscription_map_i(3) }" - - url: "{ %get_url_by_idx(4) }" - variables: - keyed_metadata: "{ %get_subscription_map_i(4) }" - - url: "{ %get_url_by_idx(5) }" - variables: - keyed_metadata: "{ %get_subscription_map_i(5) }" - - url: "{ %get_url_by_idx(6) }" - variables: - keyed_metadata: "{ %get_subscription_map_i(6) }" - - url: "{ %get_url_by_idx(7) }" - variables: - keyed_metadata: "{ %get_subscription_map_i(7) }" - - url: "{ %get_url_by_idx(8) }" - variables: - keyed_metadata: "{ %get_subscription_map_i(8) }" - diff --git a/src/ytdl_sub/prebuilt_presets/helpers/url_categorized.yaml b/src/ytdl_sub/prebuilt_presets/helpers/url_categorized.yaml new file mode 100644 index 00000000..148f913d --- /dev/null +++ b/src/ytdl_sub/prebuilt_presets/helpers/url_categorized.yaml @@ -0,0 +1,183 @@ +presets: + # Preset for categorizing URls like so + # + # subscription_name: + # category_1: + # - https://...1 + # - https://...2 + # category_2: + # - url: https://...1 + # metadata_field_1: 2011 + # metadata_field_2: 'abc" + # ... + # + # Metadata field of `url` must exist, other ones can be anything. + # Only supports a single level of nesting. + _url_categorized: + preset: + - "_multi_url_bilateral" + + overrides: + # Parameters: + # $0: url string or map containing url + metadata fields + # $1: category key + # + # Output: + # Map containing { url: ..., category: ..., metadata_field_1: ... } + "%flat_array__url_to_map_format": >- + { + %if( + %is_map($0), + %map_extend( $0, { "category": $1 } ), + { "url": $0, "category": $1 } + ) + } + + # Parameters: + # $0: category key + # $1: array of URLs in either string or map form + # + # Output: + # Array containing [{ url: ..., category: ... }, ... ] + "%flat_array__category_to_map_format": >- + { %array_apply_fixed( $1, $0, %flat_array__url_to_map_format ) } + + # Parameters: + # $0: map containing fields { url: , category: ... } + # + # Output: + # Nested map containing { : { url: , category: ... } } + "%flat_array__url_keyed_map_format": >- + { { %map_get($0, "url"): $0 } } + + # Creates an array in the form of [ { url: ..., category: ..., metadata_field_1: ... }, ... ] + category_url_array: >- + { %map_apply( subscription_dict, %flat_array__category_to_map_format ) } + + # Creates a map in the form of { : { category: ..., metadata_field_1: ... }, ... } + category_url_map: >- + { + %array_reduce( + %array_apply( category_url_array, %flat_array__url_keyed_map_format ), + %map_extend + ) + } + + # Parameters: + # $0: metadata field to fetch for the current url + # $1: default value + # + # 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 ) } + + # Parameters: + # $0: integer to fetch the i'th url using 1-based indexing + # + # 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 )} + + url: "{ %get_url_i(1) }" + url2: "{ %get_url_i(2) }" + url3: "{ %get_url_i(3) }" + url4: "{ %get_url_i(4) }" + url5: "{ %get_url_i(5) }" + url6: "{ %get_url_i(6) }" + url7: "{ %get_url_i(7) }" + url8: "{ %get_url_i(8) }" + url9: "{ %get_url_i(9) }" + url10: "{ %get_url_i(10) }" + url11: "{ %get_url_i(11) }" + url12: "{ %get_url_i(12) }" + url13: "{ %get_url_i(13) }" + url14: "{ %get_url_i(14) }" + url15: "{ %get_url_i(15) }" + url16: "{ %get_url_i(16) }" + url17: "{ %get_url_i(17) }" + url18: "{ %get_url_i(18) }" + url19: "{ %get_url_i(19) }" + url20: "{ %get_url_i(20) }" + url21: "{ %get_url_i(21) }" + url22: "{ %get_url_i(22) }" + url23: "{ %get_url_i(23) }" + url24: "{ %get_url_i(24) }" + url25: "{ %get_url_i(25) }" + url26: "{ %get_url_i(26) }" + url27: "{ %get_url_i(27) }" + url28: "{ %get_url_i(28) }" + url29: "{ %get_url_i(29) }" + url30: "{ %get_url_i(30) }" + url31: "{ %get_url_i(31) }" + url32: "{ %get_url_i(32) }" + url33: "{ %get_url_i(33) }" + url34: "{ %get_url_i(34) }" + url35: "{ %get_url_i(35) }" + url36: "{ %get_url_i(36) }" + url37: "{ %get_url_i(37) }" + url38: "{ %get_url_i(38) }" + url39: "{ %get_url_i(39) }" + url40: "{ %get_url_i(40) }" + url41: "{ %get_url_i(41) }" + url42: "{ %get_url_i(42) }" + url43: "{ %get_url_i(43) }" + url44: "{ %get_url_i(44) }" + url45: "{ %get_url_i(45) }" + url46: "{ %get_url_i(46) }" + url47: "{ %get_url_i(47) }" + url48: "{ %get_url_i(48) }" + url49: "{ %get_url_i(49) }" + url50: "{ %get_url_i(50) }" + url51: "{ %get_url_i(51) }" + url52: "{ %get_url_i(52) }" + url53: "{ %get_url_i(53) }" + url54: "{ %get_url_i(54) }" + url55: "{ %get_url_i(55) }" + url56: "{ %get_url_i(56) }" + url57: "{ %get_url_i(57) }" + url58: "{ %get_url_i(58) }" + url59: "{ %get_url_i(59) }" + url60: "{ %get_url_i(60) }" + url61: "{ %get_url_i(61) }" + url62: "{ %get_url_i(62) }" + url63: "{ %get_url_i(63) }" + url64: "{ %get_url_i(64) }" + url65: "{ %get_url_i(65) }" + url66: "{ %get_url_i(66) }" + url67: "{ %get_url_i(67) }" + url68: "{ %get_url_i(68) }" + url69: "{ %get_url_i(69) }" + url70: "{ %get_url_i(70) }" + url71: "{ %get_url_i(71) }" + url72: "{ %get_url_i(72) }" + url73: "{ %get_url_i(73) }" + url74: "{ %get_url_i(74) }" + url75: "{ %get_url_i(75) }" + url76: "{ %get_url_i(76) }" + url77: "{ %get_url_i(77) }" + url78: "{ %get_url_i(78) }" + url79: "{ %get_url_i(79) }" + url80: "{ %get_url_i(80) }" + url81: "{ %get_url_i(81) }" + url82: "{ %get_url_i(82) }" + url83: "{ %get_url_i(83) }" + url84: "{ %get_url_i(84) }" + url85: "{ %get_url_i(85) }" + url86: "{ %get_url_i(86) }" + url87: "{ %get_url_i(87) }" + url88: "{ %get_url_i(88) }" + url89: "{ %get_url_i(89) }" + url90: "{ %get_url_i(90) }" + url91: "{ %get_url_i(91) }" + url92: "{ %get_url_i(92) }" + url93: "{ %get_url_i(93) }" + url94: "{ %get_url_i(94) }" + url95: "{ %get_url_i(95) }" + url96: "{ %get_url_i(96) }" + url97: "{ %get_url_i(97) }" + url98: "{ %get_url_i(98) }" + url99: "{ %get_url_i(99) }" + url100: "{ %get_url_i(100) }" \ No newline at end of file diff --git a/src/ytdl_sub/prebuilt_presets/music_videos/music_video_extras.yaml b/src/ytdl_sub/prebuilt_presets/music_videos/music_video_extras.yaml index 9cc72d82..8104781c 100644 --- a/src/ytdl_sub/prebuilt_presets/music_videos/music_video_extras.yaml +++ b/src/ytdl_sub/prebuilt_presets/music_videos/music_video_extras.yaml @@ -24,14 +24,14 @@ presets: _music_video_extras_base: preset: - - "_keyed_url" + - "_url_categorized" - "_music_video_base" overrides: music_video_album: >- - { %map_get( %map(keyed_metadata), "key" ) } + { %get_url_field("category", music_video_album_default) } music_video_title: >- - { %map_get( keyed_metadata, "title", title ) } + { %get_url_field("title", title) } "Jellyfin Music Videos with Extras": preset: diff --git a/src/ytdl_sub/script/script.py b/src/ytdl_sub/script/script.py index f285eae6..e54cc6ba 100644 --- a/src/ytdl_sub/script/script.py +++ b/src/ytdl_sub/script/script.py @@ -152,6 +152,7 @@ class Script: lambda_function_names = set( lamb.value for lamb in SyntaxTree(function.args).lambdas if isinstance(lamb, Lambda) + and lamb in function.args ) # Only case len(lambda_function_names) > 1 is when used in if-statements diff --git a/src/ytdl_sub/utils/script.py b/src/ytdl_sub/utils/script.py index f74b835b..8f2c9b2a 100644 --- a/src/ytdl_sub/utils/script.py +++ b/src/ytdl_sub/utils/script.py @@ -9,7 +9,7 @@ from ytdl_sub.script.types.array import UnresolvedArray from ytdl_sub.script.types.function import BuiltInFunction from ytdl_sub.script.types.function import Function from ytdl_sub.script.types.map import UnresolvedMap -from ytdl_sub.script.types.resolvable import Argument +from ytdl_sub.script.types.resolvable import Argument, Lambda from ytdl_sub.script.types.resolvable import Boolean from ytdl_sub.script.types.resolvable import Float from ytdl_sub.script.types.resolvable import Integer @@ -115,6 +115,8 @@ class ScriptUtils: out = arg.name elif isinstance(arg, Function): out = f"%{arg.name}( {', '.join(cls._to_script_code(val) for val in arg.args)} )" + elif isinstance(arg, Lambda): + out = f"%{arg.value}" else: raise UNREACHABLE return f"{{ {out} }}" if top_level else out diff --git a/tests/unit/prebuilt_presets/test_prebuilt_presets.py b/tests/unit/prebuilt_presets/test_prebuilt_presets.py index d7bcf2f4..ec010cea 100644 --- a/tests/unit/prebuilt_presets/test_prebuilt_presets.py +++ b/tests/unit/prebuilt_presets/test_prebuilt_presets.py @@ -550,24 +550,17 @@ class TestPrebuiltMusicVideoPresets: album_metadata: str, multi_url: bool, ) -> Dict: - subscription_dict = f"""{{ - {{ - {album_metadata}: "https://your.name.here" - }} - }}""" + subscription_dict = { + album_metadata: [ + "https://your.name.here" + ] + } if multi_url: - subscription_dict = f"""{{ - {{ - {album_metadata}: [ - "https://your.name.here", - {{ - "url": "https://your.name.here2", - "title": "Custom Title" - }} - ] - }} - }}""" + subscription_dict[album_metadata].append({ + "url": "https://your.name.here2", + "title": "Custom Title" + }) preset_dict = { "preset": [