From 62b07a3c2b6b143dfc75e45035748eec0b54f688 Mon Sep 17 00:00:00 2001 From: Jesse Bannon Date: Wed, 6 Dec 2023 17:49:35 -0800 Subject: [PATCH] variables are king --- .../entries/script/function_scripts.py | 15 ++++- .../entries/script/variable_definitions.py | 56 +++++++------------ .../entries/script/variable_scripts.py | 41 ++++++-------- tests/unit/entries/conftest.py | 1 + tests/unit/entries/test_variable_scripts.py | 7 ++- 5 files changed, 56 insertions(+), 64 deletions(-) diff --git a/src/ytdl_sub/entries/script/function_scripts.py b/src/ytdl_sub/entries/script/function_scripts.py index 8fb5af72..40f680a3 100644 --- a/src/ytdl_sub/entries/script/function_scripts.py +++ b/src/ytdl_sub/entries/script/function_scripts.py @@ -3,6 +3,7 @@ from yt_dlp.utils import sanitize_filename from ytdl_sub.script.functions import Functions from ytdl_sub.script.types.map import Map from ytdl_sub.script.types.resolvable import Integer +from ytdl_sub.script.types.resolvable import ReturnableArgument from ytdl_sub.script.types.resolvable import String from ytdl_sub.script.utils.exceptions import RuntimeException @@ -15,14 +16,21 @@ _days_in_month = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] class CustomFunctions: + @staticmethod + def legacy_bracket_safety(value: ReturnableArgument) -> ReturnableArgument: + if isinstance(value, String): + value = String(value.value.replace("{", "{").replace("}", "}")) + return value + @staticmethod def sanitize(string: String) -> String: return String(sanitize_filename(string.value)) @staticmethod def sanitize_plex_episode(string: String) -> String: - out = CustomFunctions.sanitize(string).value - for char in out: + sanitized_string = CustomFunctions.sanitize(string).value + out = "" + for char in sanitized_string: match char: case "0": out += "0" @@ -51,7 +59,7 @@ class CustomFunctions: @staticmethod def to_date_metadata(yyyymmdd: String) -> Map: date_str = yyyymmdd.value - if not (date_str.isnumeric() and len(date_str) == 6): + if not (date_str.isnumeric() and len(date_str) == 8): raise RuntimeException( f"Expected input of date_metadata to be YYYYMMDD, but received {date_str}" ) @@ -102,6 +110,7 @@ class CustomFunctions: @staticmethod def register(): + Functions.register_function(CustomFunctions.legacy_bracket_safety) Functions.register_function(CustomFunctions.sanitize) Functions.register_function(CustomFunctions.sanitize_plex_episode) Functions.register_function(CustomFunctions.to_date_metadata) diff --git a/src/ytdl_sub/entries/script/variable_definitions.py b/src/ytdl_sub/entries/script/variable_definitions.py index 684ef453..78215e40 100644 --- a/src/ytdl_sub/entries/script/variable_definitions.py +++ b/src/ytdl_sub/entries/script/variable_definitions.py @@ -37,26 +37,6 @@ class _Variables: """ return Metadata("entry_metadata") - @property - def playlist_metadata(self) -> DerivedMetadata: - """ - Returns - ------- - dict - The playlist's info.json in dict form - """ - return DerivedMetadata("playlist_metadata", metadata_key="playlist_metadata") - - @property - def source_metadata(self) -> DerivedMetadata: - """ - Returns - ------- - dict - The source's info.json in dict form - """ - return DerivedMetadata("source_metadata", metadata_key="source_metadata") - @property def uid(self) -> MetadataVariable: """ @@ -238,7 +218,7 @@ class _Variables: Name of the source (i.e. channel with multiple playlists) if it exists, otherwise returns its playlist_title. """ - return MetadataVariable("source_title", metadata_key="title") + return MetadataVariable("source_title", metadata_key="source_title") @property def source_title_sanitized(self) -> Variable: @@ -258,7 +238,7 @@ class _Variables: str The source unique id if it exists, otherwise returns the playlist unique ID. """ - return MetadataVariable("source_uid", metadata_key="id") + return MetadataVariable("source_uid", metadata_key="source_uid") @property def source_index(self) -> MetadataVariable: @@ -271,7 +251,7 @@ class _Variables: It is recommended to not use this unless you know the source will never add new content (it is easy for this value to change). """ - return MetadataVariable("source_index", metadata_key="playlist_index") + return MetadataVariable("source_index", metadata_key="source_index") @property def source_index_padded(self) -> Variable: @@ -291,7 +271,7 @@ class _Variables: int The source count if it exists, otherwise returns the playlist count. """ - return MetadataVariable("source_count", metadata_key="playlist_count") + return MetadataVariable("source_count", metadata_key="source_count") @property def source_webpage_url(self) -> MetadataVariable: @@ -301,7 +281,7 @@ class _Variables: str The source webpage url if it exists, otherwise returns the playlist webpage url. """ - return MetadataVariable("source_webpage_url", metadata_key="webpage_url") + return MetadataVariable("source_webpage_url", metadata_key="source_webpage_url") @property def source_description(self) -> MetadataVariable: @@ -311,7 +291,7 @@ class _Variables: str The source description if it exists, otherwise returns the playlist description. """ - return MetadataVariable("source_description", metadata_key="description") + return MetadataVariable("source_description", metadata_key="source_description") @property def playlist_uid(self) -> MetadataVariable: @@ -321,7 +301,7 @@ class _Variables: str The playlist unique ID if it exists, otherwise return Variable("") """ - return MetadataVariable(variable_name="playlist_uid", metadata_key="id") + return MetadataVariable(variable_name="playlist_uid", metadata_key="playlist_uid") @property def playlist_title(self) -> MetadataVariable: @@ -331,7 +311,7 @@ class _Variables: str Name of its parent playlist/channel if it exists, otherwise returns its title. """ - return MetadataVariable(variable_name="playlist_title", metadata_key="title") + return MetadataVariable(variable_name="playlist_title", metadata_key="playlist_title") @property def playlist_title_sanitized(self) -> Variable: @@ -427,7 +407,9 @@ class _Variables: str The playlist description if it exists, otherwise returns the entry's description. """ - return MetadataVariable(variable_name="playlist_description", metadata_key="description") + return MetadataVariable( + variable_name="playlist_description", metadata_key="playlist_description" + ) @property def playlist_webpage_url(self) -> MetadataVariable: @@ -437,7 +419,9 @@ class _Variables: str The playlist webpage url if it exists. Otherwise, returns the entry webpage url. """ - return MetadataVariable(variable_name="playlist_webpage_url", metadata_key="webpage_url") + return MetadataVariable( + variable_name="playlist_webpage_url", metadata_key="playlist_webpage_url" + ) @property def playlist_max_upload_year(self) -> MetadataVariable: @@ -472,7 +456,7 @@ class _Variables: str The playlist uploader id if it exists, otherwise returns the entry uploader ID. """ - return MetadataVariable("playlist_uploader_id", metadata_key="uploader_id") + return MetadataVariable("playlist_uploader_id", metadata_key="playlist_uploader_id") @property def playlist_uploader(self) -> MetadataVariable: @@ -482,7 +466,7 @@ class _Variables: str The playlist uploader if it exists, otherwise return Variable("") """ - return MetadataVariable("playlist_uploader", metadata_key="uploader") + return MetadataVariable("playlist_uploader", metadata_key="playlist_uploader") @property def playlist_uploader_sanitized(self) -> Variable: @@ -502,7 +486,7 @@ class _Variables: str The playlist uploader url if it exists, otherwise returns the playlist webpage_url. """ - return MetadataVariable("playlist_uploader_url", metadata_key="uploader_url") + return MetadataVariable("playlist_uploader_url", metadata_key="playlist_uploader_url") @property def source_uploader_id(self) -> MetadataVariable: @@ -512,7 +496,7 @@ class _Variables: str The source uploader id if it exists, otherwise returns the playlist_uploader_id """ - return MetadataVariable("source_uploader_id", metadata_key="uploader_id") + return MetadataVariable("source_uploader_id", metadata_key="source_uploader_id") @property def source_uploader(self) -> MetadataVariable: @@ -522,7 +506,7 @@ class _Variables: str The source uploader if it exists, otherwise return Variable("") """ - return MetadataVariable("source_uploader", metadata_key="uploader") + return MetadataVariable("source_uploader", metadata_key="source_uploader") @property def source_uploader_url(self) -> MetadataVariable: @@ -532,7 +516,7 @@ class _Variables: str The source uploader url if it exists, otherwise returns the source webpage_url. """ - return MetadataVariable("source_uploader_url", metadata_key="uploader_url") + return MetadataVariable("source_uploader_url", metadata_key="source_uploader_url") @property def creator(self) -> MetadataVariable: diff --git a/src/ytdl_sub/entries/script/variable_scripts.py b/src/ytdl_sub/entries/script/variable_scripts.py index c17c0959..e2f37f53 100644 --- a/src/ytdl_sub/entries/script/variable_scripts.py +++ b/src/ytdl_sub/entries/script/variable_scripts.py @@ -5,7 +5,6 @@ import mergedeep from ytdl_sub.entries.script.function_scripts import CustomFunctions from ytdl_sub.entries.script.variable_definitions import VARIABLES as v -from ytdl_sub.entries.script.variable_definitions import DerivedMetadata from ytdl_sub.entries.script.variable_definitions import Metadata from ytdl_sub.entries.script.variable_definitions import MetadataVariable from ytdl_sub.entries.script.variable_definitions import Variable @@ -39,13 +38,15 @@ def _get_internal( ) -> str: if default is None: # TODO: assert with good error message if key DNE - return f"%map_get({metadata.variable_name}, '{key.metadata_key}')" - if isinstance(default, Variable): - return f"%map_get({metadata.variable_name}, '{key.metadata_key}', {default.variable_name})" - if isinstance(default, str): - return f"%map_get({metadata.variable_name}, '{key.metadata_key}', '{default}')" + out = f"%map_get({metadata.variable_name}, '{key.metadata_key}')" + elif isinstance(default, Variable): + out = f"%map_get({metadata.variable_name}, '{key.metadata_key}', {default.variable_name})" + elif isinstance(default, str): + out = f"%map_get({metadata.variable_name}, '{key.metadata_key}', '{default}')" + else: + out = f"%map_get({metadata.variable_name}, '{key.metadata_key}', {default})" - return f"%map_get({metadata.variable_name}, '{key.metadata_key}', {default})" + return f"%legacy_bracket_safety({out})" def _get_int( @@ -75,11 +76,11 @@ def entry_get_int(key: MetadataVariable, default: Optional[Variable | int] = Non def playlist_get(key: MetadataVariable, default: Optional[Variable | str | int] = None) -> str: - return _get(metadata=v.playlist_metadata, key=key, default=default) + return _get(metadata=v.entry_metadata, key=key, default=default) def playlist_get_int(key: MetadataVariable, default: Optional[Variable | int] = None) -> str: - return _get_int(metadata=v.playlist_metadata, key=key, default=default) + return _get_int(metadata=v.entry_metadata, key=key, default=default) ############################################################################################### @@ -87,21 +88,16 @@ def playlist_get_int(key: MetadataVariable, default: Optional[Variable | int] = def source_get(key: MetadataVariable, default: Optional[Variable | str | int] = None) -> str: - return _get(metadata=v.source_metadata, key=key, default=default) + return _get(metadata=v.entry_metadata, key=key, default=default) def source_get_int(key: MetadataVariable, default: Optional[Variable | int] = None) -> str: - return _get_int(metadata=v.source_metadata, key=key, default=default) + return _get_int(metadata=v.entry_metadata, key=key, default=default) ############################################################################################### # Scripts -ENTRY_METADATA: Dict[DerivedMetadata, str] = { - v.playlist_metadata: entry_get(v.playlist_metadata), - v.source_metadata: entry_get(v.source_metadata), -} - ENTRY_HARDCODED_VARIABLES: Dict[Variable, str] = { v.info_json_ext: "info.json", @@ -132,8 +128,8 @@ ENTRY_DEFAULT_VARIABLES: Dict[MetadataVariable, str] = { } ENTRY_INJECTED_VARIABLES: Dict[MetadataVariable, str] = { - v.download_index: entry_get_int(v.download_index), - v.upload_date_index: entry_get_int(v.upload_date_index), + v.download_index: entry_get_int(v.download_index, 1), + v.upload_date_index: entry_get_int(v.upload_date_index, 1), } ENTRY_DERIVED_VARIABLES: Dict[Variable, str] = { @@ -193,7 +189,7 @@ ENTRY_RELEASE_DATE_VARIABLES: Dict[Variable, str] = { v.release_date_standardized: date_metadata(v.release_date, "date_standardized"), } -PLAYLIST_VARIABLES: Dict[MetadataVariable, str] = { +PLAYLIST_VARIABLES: Dict[Variable, str] = { v.playlist_uid: playlist_get(v.playlist_uid, v.uid), v.playlist_title: playlist_get(v.playlist_title, v.title), v.playlist_webpage_url: playlist_get(v.playlist_webpage_url, v.webpage_url), @@ -204,13 +200,13 @@ PLAYLIST_VARIABLES: Dict[MetadataVariable, str] = { v.playlist_uploader_url: playlist_get(v.playlist_uploader_url, v.playlist_webpage_url), } -PLAYLIST_INJECTED_VARIABLES: Dict[MetadataVariable, str] = { +PLAYLIST_INJECTED_VARIABLES: Dict[Variable, str] = { v.playlist_max_upload_year: playlist_get(v.playlist_max_upload_year, v.upload_year) } PLAYLIST_DERIVED_VARIABLES: Dict[Variable, str] = { v.playlist_title_sanitized: sanitized(v.playlist_title), - v.playlist_index_reversed: f"{{%sub({v.playlist_count.variable_name}, {v.playlist_index.variable_name}, 1)}}", + v.playlist_index_reversed: f"{{%sub({v.playlist_count.variable_name}, {v.playlist_index.variable_name}, -1)}}", v.playlist_index_padded: pad_int(v.playlist_index, 2), v.playlist_index_reversed_padded: pad_int(v.playlist_index_reversed, 2), v.playlist_index_padded6: pad_int(v.playlist_index, 6), @@ -220,7 +216,7 @@ PLAYLIST_DERIVED_VARIABLES: Dict[Variable, str] = { } -SOURCE_VARIABLES: Dict[MetadataVariable, str] = { +SOURCE_VARIABLES: Dict[Variable, str] = { v.source_uid: source_get(v.source_uid, v.playlist_uid), v.source_title: source_get(v.source_title, v.playlist_title), v.source_webpage_url: source_get(v.source_webpage_url, v.playlist_webpage_url), @@ -240,7 +236,6 @@ SOURCE_DERIVED_VARIABLES: Dict[Variable, str] = { _VARIABLE_SCRIPTS: Dict[Variable, str] = {} mergedeep.merge( _VARIABLE_SCRIPTS, - ENTRY_METADATA, ENTRY_HARDCODED_VARIABLES, ENTRY_REQUIRED_VARIABLES, ENTRY_DEFAULT_VARIABLES, diff --git a/tests/unit/entries/conftest.py b/tests/unit/entries/conftest.py index 16199c7d..6fdf8e62 100644 --- a/tests/unit/entries/conftest.py +++ b/tests/unit/entries/conftest.py @@ -162,6 +162,7 @@ def mock_entry_kwargs( return { "id": uid, "epoch": 1596878400, + "ie_key": "test_ie_key", "extractor": extractor, "title": title, "ext": ext, diff --git a/tests/unit/entries/test_variable_scripts.py b/tests/unit/entries/test_variable_scripts.py index ca0a3733..305baeb9 100644 --- a/tests/unit/entries/test_variable_scripts.py +++ b/tests/unit/entries/test_variable_scripts.py @@ -11,5 +11,8 @@ class TestEntry(object): entry_metadata: Dict[str, str] = { VARIABLES.entry_metadata.variable_name: f"{{{json.dumps(mock_entry._kwargs)}}}" } - script = Script(dict(entry_metadata, **VARIABLE_SCRIPTS)).resolve() - assert script == mock_entry_to_dict + script = Script(dict(entry_metadata, **VARIABLE_SCRIPTS)) + output = {var_name: var_output.native for var_name, var_output in script.resolve().items()} + del output[VARIABLES.entry_metadata.variable_name] + del output[VARIABLES.ie_key.variable_name] + assert output == mock_entry_to_dict