Skip to content

Commit

Permalink
[BACKEND] %contains_any function, list + dict support for tilda ove…
Browse files Browse the repository at this point in the history
…rrides mode (#1054)

Adds the function `%contains_any`, and list support in a tilda override subscription. The end-goal of these features are to more easily add a title exclude list, like so:

```
__preset__:
  filter_exclude:
    - "{%contains_any( %lower(title), exclude_title_strings )}"

...
Jellyfin TV Show by Date:
  ~History Documentaries:
    url: "https://..."
    exclude_title_strings:
      - "trailer"
      - "preview"
```

A proper prebuilt preset or built-in functionality will follow this change.
  • Loading branch information
jmbannon authored Sep 20, 2024
1 parent 7599483 commit 10cb82a
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,13 @@ contains
:description:
Returns True if ``contains`` is in ``string``. False otherwise.

contains_any
~~~~~~~~~~~~
:spec: ``contains_any(string: String, contains_array: Array) -> Boolean``

:description:
Returns true if any element in ``contains_array`` is in ``string``. False otherwise.

lower
~~~~~
:spec: ``lower(string: String) -> String``
Expand Down
15 changes: 15 additions & 0 deletions src/ytdl_sub/script/functions/string_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from ytdl_sub.script.types.array import Array
from ytdl_sub.script.types.resolvable import AnyArgument
from ytdl_sub.script.types.resolvable import Boolean
from ytdl_sub.script.types.resolvable import Float
from ytdl_sub.script.types.resolvable import Integer
from ytdl_sub.script.types.resolvable import Numeric
from ytdl_sub.script.types.resolvable import String
Expand All @@ -25,6 +26,20 @@ def contains(string: String, contains: String) -> Boolean:
"""
return Boolean(contains.value in string.value)

@staticmethod
def contains_any(string: String, contains_array: Array) -> Boolean:
"""
:description:
Returns true if any element in ``contains_array`` is in ``string``. False otherwise.
"""
return Boolean(
any(
str(val) in string.value
for val in contains_array.value
if isinstance(val, (String, Integer, Boolean, Float))
)
)

@staticmethod
def slice(string: String, start: Integer, end: Optional[Integer] = None) -> String:
"""
Expand Down
6 changes: 4 additions & 2 deletions src/ytdl_sub/subscriptions/subscription_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from ytdl_sub.config.overrides import Overrides
from ytdl_sub.entries.variables.override_variables import SubscriptionVariables
from ytdl_sub.utils.script import ScriptUtils
from ytdl_sub.validators.string_formatter_validators import DictFormatterValidator
from ytdl_sub.validators.string_formatter_validators import UnstructuredDictFormatterValidator
from ytdl_sub.validators.validators import DictValidator
from ytdl_sub.validators.validators import LiteralDictValidator
from ytdl_sub.validators.validators import StringListValidator
Expand Down Expand Up @@ -196,7 +196,9 @@ def __init__(
)


class SubscriptionWithOverridesValidator(SubscriptionLeafValidator, DictFormatterValidator):
class SubscriptionWithOverridesValidator(
SubscriptionLeafValidator, UnstructuredDictFormatterValidator
):
def __init__(
self,
name,
Expand Down
8 changes: 8 additions & 0 deletions tests/unit/config/test_subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ def preset_with_subscription_overrides_tilda(
"parent_preset_2 | parent_preset_1": {
"~ test_2_1": {
"current_override": "test_2_1",
"custom_list": [
"elem1",
"elem2",
"elem3",
],
"passed_list_elem": "{%contains_any('elem2', custom_list)}",
}
},
},
Expand Down Expand Up @@ -262,6 +268,8 @@ def test_subscription_overrides_tilda(

assert sub_2_1.get("subscription_name").native == "test_2_1"
assert sub_2_1.get("current_override").native == "test_2_1" # tilda sub takes precedence
assert sub_2_1.get("passed_list_elem").native is True
assert sub_2_1.get("custom_list").native == ["elem1", "elem2", "elem3"]


def test_subscription_overrides_map(
Expand Down
8 changes: 8 additions & 0 deletions tests/unit/script/functions/test_string_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,14 @@ def test_contains(self, value, expected_output):
output = single_variable_output(f"{{%contains('a brown dog', '{value}')}}")
assert output == expected_output

@pytest.mark.parametrize(
"value, expected_output",
[("['a', 'b', 'c']", True), ("['nope', [], {}]", False), ("['at', 'dog']", True)],
)
def test_contains_any(self, value, expected_output):
output = single_variable_output(f"{{%contains_any('a brown dog', {value})}}")
assert output == expected_output

@pytest.mark.parametrize(
"input_string, split, max_split, expected_output",
[
Expand Down

0 comments on commit 10cb82a

Please sign in to comment.