[BACKEND] %contains_any function, list + dict support for tilda overrides 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.
This commit is contained in:
parent
759948361f
commit
10cb82a69a
5 changed files with 42 additions and 2 deletions
|
|
@ -595,6 +595,13 @@ contains
|
||||||
:description:
|
:description:
|
||||||
Returns True if ``contains`` is in ``string``. False otherwise.
|
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
|
lower
|
||||||
~~~~~
|
~~~~~
|
||||||
:spec: ``lower(string: String) -> String``
|
:spec: ``lower(string: String) -> String``
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ from typing import Optional
|
||||||
from ytdl_sub.script.types.array import Array
|
from ytdl_sub.script.types.array import Array
|
||||||
from ytdl_sub.script.types.resolvable import AnyArgument
|
from ytdl_sub.script.types.resolvable import AnyArgument
|
||||||
from ytdl_sub.script.types.resolvable import Boolean
|
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 Integer
|
||||||
from ytdl_sub.script.types.resolvable import Numeric
|
from ytdl_sub.script.types.resolvable import Numeric
|
||||||
from ytdl_sub.script.types.resolvable import String
|
from ytdl_sub.script.types.resolvable import String
|
||||||
|
|
@ -25,6 +26,20 @@ class StringFunctions:
|
||||||
"""
|
"""
|
||||||
return Boolean(contains.value in string.value)
|
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
|
@staticmethod
|
||||||
def slice(string: String, start: Integer, end: Optional[Integer] = None) -> String:
|
def slice(string: String, start: Integer, end: Optional[Integer] = None) -> String:
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ from ytdl_sub.config.config_file import ConfigFile
|
||||||
from ytdl_sub.config.overrides import Overrides
|
from ytdl_sub.config.overrides import Overrides
|
||||||
from ytdl_sub.entries.variables.override_variables import SubscriptionVariables
|
from ytdl_sub.entries.variables.override_variables import SubscriptionVariables
|
||||||
from ytdl_sub.utils.script import ScriptUtils
|
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 DictValidator
|
||||||
from ytdl_sub.validators.validators import LiteralDictValidator
|
from ytdl_sub.validators.validators import LiteralDictValidator
|
||||||
from ytdl_sub.validators.validators import StringListValidator
|
from ytdl_sub.validators.validators import StringListValidator
|
||||||
|
|
@ -196,7 +196,9 @@ class SubscriptionListValuesValidator(SubscriptionLeafValidator, StringListValid
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SubscriptionWithOverridesValidator(SubscriptionLeafValidator, DictFormatterValidator):
|
class SubscriptionWithOverridesValidator(
|
||||||
|
SubscriptionLeafValidator, UnstructuredDictFormatterValidator
|
||||||
|
):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
name,
|
name,
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,12 @@ def preset_with_subscription_overrides_tilda(
|
||||||
"parent_preset_2 | parent_preset_1": {
|
"parent_preset_2 | parent_preset_1": {
|
||||||
"~ test_2_1": {
|
"~ test_2_1": {
|
||||||
"current_override": "test_2_1",
|
"current_override": "test_2_1",
|
||||||
|
"custom_list": [
|
||||||
|
"elem1",
|
||||||
|
"elem2",
|
||||||
|
"elem3",
|
||||||
|
],
|
||||||
|
"passed_list_elem": "{%contains_any('elem2', custom_list)}",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -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("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("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(
|
def test_subscription_overrides_map(
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,14 @@ class TestNumericFunctions:
|
||||||
output = single_variable_output(f"{{%contains('a brown dog', '{value}')}}")
|
output = single_variable_output(f"{{%contains('a brown dog', '{value}')}}")
|
||||||
assert output == expected_output
|
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(
|
@pytest.mark.parametrize(
|
||||||
"input_string, split, max_split, expected_output",
|
"input_string, split, max_split, expected_output",
|
||||||
[
|
[
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue