[FEATURE] Add --dl-override to pass dl arg overrides to all subscriptions (#882)
With both `--match` and `--dl-override`, it is now possible to more easily experiment with subscriptions without needing to create a separate file. For example, suppose you are changing some values in your subscription "Rick A" and want to test them out. You can now run: ``` ytdl-sub sub --dry-run --match Rick --dl-override '--ytdl-options.max_downloads 3' ``` This will 1. Dry-run 2. Only run for the subscription "Rick A" 3. Apply setting max_downloads to 3
This commit is contained in:
parent
9382be5c42
commit
78cdcce464
6 changed files with 75 additions and 2 deletions
|
|
@ -3,6 +3,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Dict
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
|
@ -70,6 +71,7 @@ def _download_subscriptions_from_yaml_files(
|
||||||
config: ConfigFile,
|
config: ConfigFile,
|
||||||
subscription_paths: List[str],
|
subscription_paths: List[str],
|
||||||
subscription_matches: List[str],
|
subscription_matches: List[str],
|
||||||
|
subscription_override_dict: Dict,
|
||||||
update_with_info_json: bool,
|
update_with_info_json: bool,
|
||||||
dry_run: bool,
|
dry_run: bool,
|
||||||
) -> List[Subscription]:
|
) -> List[Subscription]:
|
||||||
|
|
@ -102,7 +104,11 @@ def _download_subscriptions_from_yaml_files(
|
||||||
|
|
||||||
# Load all the subscriptions first to perform all validation before downloading
|
# Load all the subscriptions first to perform all validation before downloading
|
||||||
for path in subscription_paths:
|
for path in subscription_paths:
|
||||||
subscriptions += Subscription.from_file_path(config=config, subscription_path=path)
|
subscriptions += Subscription.from_file_path(
|
||||||
|
config=config,
|
||||||
|
subscription_path=path,
|
||||||
|
subscription_override_dict=subscription_override_dict,
|
||||||
|
)
|
||||||
|
|
||||||
if subscriptions and subscription_matches:
|
if subscriptions and subscription_matches:
|
||||||
logger.info("Filtering subscriptions by name based on --match arguments")
|
logger.info("Filtering subscriptions by name based on --match arguments")
|
||||||
|
|
@ -233,11 +239,18 @@ def main() -> List[Subscription]:
|
||||||
"full backup before usage. You have been warned!",
|
"full backup before usage. You have been warned!",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
subscription_override_dict = {}
|
||||||
|
if args.dl_override:
|
||||||
|
subscription_override_dict = DownloadArgsParser.from_dl_override(
|
||||||
|
override=args.dl_override, config=config
|
||||||
|
).to_subscription_dict()
|
||||||
|
|
||||||
logger.info("Validating subscriptions...")
|
logger.info("Validating subscriptions...")
|
||||||
subscriptions = _download_subscriptions_from_yaml_files(
|
subscriptions = _download_subscriptions_from_yaml_files(
|
||||||
config=config,
|
config=config,
|
||||||
subscription_paths=args.subscription_paths,
|
subscription_paths=args.subscription_paths,
|
||||||
subscription_matches=args.match,
|
subscription_matches=args.match,
|
||||||
|
subscription_override_dict=subscription_override_dict,
|
||||||
update_with_info_json=args.update_with_info_json,
|
update_with_info_json=args.update_with_info_json,
|
||||||
dry_run=args.dry_run,
|
dry_run=args.dry_run,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ from typing import Tuple
|
||||||
from mergedeep import mergedeep
|
from mergedeep import mergedeep
|
||||||
|
|
||||||
from ytdl_sub.cli.parsers.main import MainArguments
|
from ytdl_sub.cli.parsers.main import MainArguments
|
||||||
|
from ytdl_sub.config.config_file import ConfigFile
|
||||||
from ytdl_sub.config.config_validator import ConfigOptions
|
from ytdl_sub.config.config_validator import ConfigOptions
|
||||||
from ytdl_sub.utils.exceptions import InvalidDlArguments
|
from ytdl_sub.utils.exceptions import InvalidDlArguments
|
||||||
|
|
||||||
|
|
@ -247,3 +248,12 @@ class DownloadArgsParser:
|
||||||
"""
|
"""
|
||||||
hash_string = str(sorted(self._unknown_arguments))
|
hash_string = str(sorted(self._unknown_arguments))
|
||||||
return hashlib.sha256(hash_string.encode()).hexdigest()[-8:]
|
return hashlib.sha256(hash_string.encode()).hexdigest()[-8:]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dl_override(cls, override: str, config: ConfigFile) -> "DownloadArgsParser":
|
||||||
|
"""
|
||||||
|
Create a DownloadArgsParser from a sub --override argument value
|
||||||
|
"""
|
||||||
|
return DownloadArgsParser(
|
||||||
|
extra_arguments=override.split(), config_options=config.config_options
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,10 @@ class SubArguments:
|
||||||
short="-u",
|
short="-u",
|
||||||
long="--update-with-info-json",
|
long="--update-with-info-json",
|
||||||
)
|
)
|
||||||
|
OVERRIDE = CLIArgument(
|
||||||
|
short="-o",
|
||||||
|
long="--dl-override",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
subscription_parser = subparsers.add_parser("sub")
|
subscription_parser = subparsers.add_parser("sub")
|
||||||
|
|
@ -175,6 +179,13 @@ subscription_parser.add_argument(
|
||||||
help="update all subscriptions with the current config using info.json files",
|
help="update all subscriptions with the current config using info.json files",
|
||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
|
subscription_parser.add_argument(
|
||||||
|
SubArguments.OVERRIDE.short,
|
||||||
|
SubArguments.OVERRIDE.long,
|
||||||
|
type=str,
|
||||||
|
help="override all subscription config values using `dl` syntax, "
|
||||||
|
"i.e. --dl-override='--ytdl_options.max_downloads 3'",
|
||||||
|
)
|
||||||
|
|
||||||
###################################################################################################
|
###################################################################################################
|
||||||
# DOWNLOAD PARSER
|
# DOWNLOAD PARSER
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from mergedeep import mergedeep
|
||||||
|
|
||||||
from ytdl_sub.config.config_file import ConfigFile
|
from ytdl_sub.config.config_file import ConfigFile
|
||||||
from ytdl_sub.config.preset import Preset
|
from ytdl_sub.config.preset import Preset
|
||||||
|
|
@ -69,7 +72,10 @@ class Subscription(SubscriptionDownload):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_file_path(
|
def from_file_path(
|
||||||
cls, config: ConfigFile, subscription_path: str | Path
|
cls,
|
||||||
|
config: ConfigFile,
|
||||||
|
subscription_path: str | Path,
|
||||||
|
subscription_override_dict: Optional[Dict] = None,
|
||||||
) -> List["Subscription"]:
|
) -> List["Subscription"]:
|
||||||
"""
|
"""
|
||||||
Loads subscriptions from a file.
|
Loads subscriptions from a file.
|
||||||
|
|
@ -80,6 +86,8 @@ class Subscription(SubscriptionDownload):
|
||||||
Validated instance of the config
|
Validated instance of the config
|
||||||
subscription_path:
|
subscription_path:
|
||||||
File path to the subscription yaml file
|
File path to the subscription yaml file
|
||||||
|
subscription_override_dict:
|
||||||
|
Optional dict containing overrides to every subscription
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
|
@ -122,6 +130,13 @@ class Subscription(SubscriptionDownload):
|
||||||
)
|
)
|
||||||
|
|
||||||
for subscription_key, subscription_object in subscriptions_dicts.items():
|
for subscription_key, subscription_object in subscriptions_dicts.items():
|
||||||
|
# Hard-override subscriptions here
|
||||||
|
mergedeep.merge(
|
||||||
|
subscription_object,
|
||||||
|
subscription_override_dict or {},
|
||||||
|
strategy=mergedeep.Strategy.ADDITIVE,
|
||||||
|
)
|
||||||
|
|
||||||
subscriptions.append(
|
subscriptions.append(
|
||||||
cls.from_dict(
|
cls.from_dict(
|
||||||
config=config,
|
config=config,
|
||||||
|
|
|
||||||
|
|
@ -199,3 +199,26 @@ class TestPlaylist:
|
||||||
dry_run=dry_run,
|
dry_run=dry_run,
|
||||||
expected_download_summary_file_name="youtube/test_playlist.json",
|
expected_download_summary_file_name="youtube/test_playlist.json",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_playlist_download_from_cli_sub_with_override_arg(
|
||||||
|
self,
|
||||||
|
preset_dict_to_subscription_yaml_generator,
|
||||||
|
playlist_preset_dict,
|
||||||
|
output_directory,
|
||||||
|
):
|
||||||
|
# TODO: Fix CLI parsing on windows when dealing with spaces
|
||||||
|
if IS_WINDOWS:
|
||||||
|
return
|
||||||
|
|
||||||
|
# No config needed when using only prebuilt presets
|
||||||
|
with preset_dict_to_subscription_yaml_generator(
|
||||||
|
subscription_name="music_video_playlist_test", preset_dict=playlist_preset_dict
|
||||||
|
) as subscription_path:
|
||||||
|
args = (
|
||||||
|
f"--dry-run sub '{subscription_path}' --dl-override '--date_range.after 20240101'"
|
||||||
|
)
|
||||||
|
|
||||||
|
subscriptions = mock_run_from_cli(args=args)
|
||||||
|
|
||||||
|
assert len(subscriptions) == 1
|
||||||
|
assert subscriptions[0].transaction_log.is_empty
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ def test_subscription_logs_write_to_file(
|
||||||
config=config,
|
config=config,
|
||||||
subscription_paths=subscription_paths,
|
subscription_paths=subscription_paths,
|
||||||
subscription_matches=match,
|
subscription_matches=match,
|
||||||
|
subscription_override_dict={},
|
||||||
update_with_info_json=False,
|
update_with_info_json=False,
|
||||||
dry_run=dry_run,
|
dry_run=dry_run,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue