Skip to content

Commit

Permalink
[FEATURE] Extend subscription syntax (#790)
Browse files Browse the repository at this point in the history
Extends the subscription.yaml syntax at the cost of introducing a breaking change.

# New Syntax
## Mix-n-match presets and indent variables
```
# Can mix/match presets and indent override variables.
# Uses presets TV Show, Only Recent and assigns Kids, TV-Y to subscription_indent_1 and _2
TV Show | = Kids | = TV-Y | Only Recent:
  "Jake Trains": "https://..."
```

## Subscriptions with list-value support
```
TV Show | = Kids | = TV-Y | Only Recent:
  "Jake Trains":
    - "https://url.1..."  # Assigns to subscription_value and subscription_value_1
    - "https://url.2..."  # Assigns to subscription_value_2
```

## Subscriptions with override-keys support
```
TV Show | = Kids | = TV-Y | Only Recent:
  "~Jake Trains":  # the ~ means "all keys underneath get assigned as override variables"
    url: "https://url.1..."  # Assigns to url
    url2: "https://url.2..."  # Assigns to url2
```

# Breaking Changes
In the TV show subscriptions example (https://github.com/jmbannon/ytdl-sub/blob/master/examples/tv_show_subscriptions.yaml), it had
```
TV Show Full Archive:
  # Sets "Kids" for genre, "TV-Y" for content rating
  = Kids | TV-Y:
    "Jake Trains": "https://www.youtube.com/@JakeTrains"
    "Kids Toys Play": "https://www.youtube.com/@KidsToysPlayChannel"
```
This must be changed to
```
TV Show Full Archive:
  # Sets "Kids" for genre, "TV-Y" for content rating
  = Kids | = TV-Y:  # Each indent variable assignment must have an = before it
    "Jake Trains": "https://www.youtube.com/@JakeTrains"
    "Kids Toys Play": "https://www.youtube.com/@KidsToysPlayChannel"
```
  • Loading branch information
jmbannon authored Nov 2, 2023
1 parent 056b111 commit 9f408d2
Show file tree
Hide file tree
Showing 6 changed files with 382 additions and 103 deletions.
4 changes: 2 additions & 2 deletions examples/tv_show_subscriptions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ TV Show Full Archive:
"Opeth": "https://www.youtube.com/channel/UCmQSJTFZaXN85gYk6W3XbdQ"

# Sets "Kids" for genre, "TV-Y" for content rating
= Kids | TV-Y:
= Kids | = TV-Y:
"Jake Trains": "https://www.youtube.com/@JakeTrains"
"Kids Toys Play": "https://www.youtube.com/@KidsToysPlayChannel"


# All subscriptions under this will use the `TV Show Only Recent` preset
TV Show Only Recent:
= News | TV-14:
= News | = TV-14:
"BBC": "https://www.youtube.com/@BBCNews"
5 changes: 3 additions & 2 deletions src/ytdl_sub/config/config_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from ytdl_sub.config.defaults import DEFAULT_LOCK_DIRECTORY
from ytdl_sub.config.defaults import MAX_FILE_NAME_BYTES
from ytdl_sub.prebuilt_presets import PREBUILT_PRESETS
from ytdl_sub.subscriptions.utils import SUBSCRIPTION_VALUE_CONFIG_KEY
from ytdl_sub.validators.file_path_validators import FFmpegFileValidator
from ytdl_sub.validators.file_path_validators import FFprobeFileValidator
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
Expand Down Expand Up @@ -106,7 +107,7 @@ class ConfigOptions(StrictDictValidator):
"ffprobe_path",
"file_name_max_bytes",
"experimental",
"subscription_value",
SUBSCRIPTION_VALUE_CONFIG_KEY,
}

def __init__(self, name: str, value: Any):
Expand Down Expand Up @@ -142,7 +143,7 @@ def __init__(self, name: str, value: Any):
key="file_name_max_bytes", validator=IntValidator, default=MAX_FILE_NAME_BYTES
)
self._subscription_value = self._validate_key_if_present(
key="subscription_value", validator=StringValidator
key=SUBSCRIPTION_VALUE_CONFIG_KEY, validator=StringValidator
)

@property
Expand Down
66 changes: 29 additions & 37 deletions src/ytdl_sub/config/preset_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from ytdl_sub.config.defaults import DEFAULT_DOWNLOAD_ARCHIVE_NAME
from ytdl_sub.entries.entry import Entry
from ytdl_sub.subscriptions.utils import SUBSCRIPTION_NAME
from ytdl_sub.utils.exceptions import ValidationException
from ytdl_sub.validators.file_path_validators import OverridesStringFormatterFilePathValidator
from ytdl_sub.validators.file_path_validators import StringFormatterFileNameValidator
Expand Down Expand Up @@ -120,45 +121,9 @@ class YTDLOptions(LiteralDictValidator):
"""


class OverridesVariables(DictFormatterValidator):
"""
Override variables that are automatically added to every subscription.
"""

def _add_override_variable(self, key_name: str, format_string: str, sanitize: bool = False):
if sanitize:
key_name = f"{key_name}_sanitized"
format_string = sanitize_filename(format_string)

self._value[key_name] = StringFormatterValidator(
name="__should_never_fail__",
value=format_string,
)

def __init__(self, name, value):
super().__init__(name, value)

# Add sanitized and non-sanitized override variables
for sanitize in [True, False]:
self._add_override_variable(
key_name="subscription_name",
format_string=self.subscription_name,
sanitize=sanitize,
)

@property
def subscription_name(self) -> str:
"""
Returns
-------
Name of the subscription
"""
return self._root_name


# Disable for proper docstring formatting
# pylint: disable=line-too-long
class Overrides(OverridesVariables):
class Overrides(DictFormatterValidator):
"""
Optional. This section allows you to define variables that can be used in any string formatter.
For example, if you want your file and thumbnail files to match without copy-pasting a large
Expand Down Expand Up @@ -188,6 +153,16 @@ class Overrides(OverridesVariables):

# pylint: enable=line-too-long

def _add_override_variable(self, key_name: str, format_string: str, sanitize: bool = False):
if sanitize:
key_name = f"{key_name}_sanitized"
format_string = sanitize_filename(format_string)

self._value[key_name] = StringFormatterValidator(
name="__should_never_fail__",
value=format_string,
)

def __init__(self, name, value):
super().__init__(name, value)

Expand All @@ -199,6 +174,23 @@ def __init__(self, name, value):
sanitize=True,
)

if SUBSCRIPTION_NAME not in self._value:
for sanitized in [True, False]:
self._add_override_variable(
key_name=SUBSCRIPTION_NAME,
format_string=self.subscription_name,
sanitize=sanitized,
)

@property
def subscription_name(self) -> str:
"""
Returns
-------
Name of the subscription
"""
return self._root_name

def apply_formatter(
self,
formatter: StringFormatterValidator,
Expand Down
Loading

0 comments on commit 9f408d2

Please sign in to comment.