diff --git a/docs/usage.rst b/docs/usage.rst index 942bd5d4..cc42640e 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -69,6 +69,12 @@ View Options ----------------- .. code-block:: - ytdl-sub view [URL] + ytdl-sub view [-sc] [URL] + +.. code-block:: text + + -sc, --split-chapters + View source variables after splitting by chapters + Preview the source variables for a given URL. Helps when creating new configs. diff --git a/src/ytdl_sub/cli/download_args_parser.py b/src/ytdl_sub/cli/download_args_parser.py index 4a1afb95..bac6bf15 100644 --- a/src/ytdl_sub/cli/download_args_parser.py +++ b/src/ytdl_sub/cli/download_args_parser.py @@ -41,7 +41,7 @@ class DownloadArgsParser: self._config_options = config_options for arg in extra_arguments: - if arg in MainArguments.all(): + if arg in MainArguments.all_arguments(): raise InvalidDlArguments( f"'{arg}' is a ytdl-sub argument and must placed behind 'dl'" ) diff --git a/src/ytdl_sub/cli/main.py b/src/ytdl_sub/cli/main.py index 85042164..00564b99 100644 --- a/src/ytdl_sub/cli/main.py +++ b/src/ytdl_sub/cli/main.py @@ -5,11 +5,9 @@ from typing import List from typing import Tuple from ytdl_sub.cli.download_args_parser import DownloadArgsParser -from ytdl_sub.cli.main_args_parser import MainArguments from ytdl_sub.cli.main_args_parser import parser from ytdl_sub.config.config_file import ConfigFile from ytdl_sub.subscriptions.subscription import Subscription -from ytdl_sub.utils.exceptions import ValidationException from ytdl_sub.utils.file_handler import FileHandlerTransactionLog from ytdl_sub.utils.file_lock import working_directory_lock from ytdl_sub.utils.logger import Logger @@ -46,10 +44,6 @@ def _download_subscriptions_from_yaml_files( subscriptions: List[Subscription] = [] output: List[Tuple[Subscription, FileHandlerTransactionLog]] = [] - # Make sure no main args are passed as a subscription path - if main_argument := MainArguments.get_argument_if_exists(subscription_paths) is not None: - raise ValidationException(f"The argument '{main_argument}' must be passed before 'sub'") - # Load all the subscriptions first to perform all validation before downloading for path in subscription_paths: subscriptions += Subscription.from_file_path(config=config, subscription_path=path) diff --git a/src/ytdl_sub/cli/main_args_parser.py b/src/ytdl_sub/cli/main_args_parser.py index 5b03355e..bd697521 100644 --- a/src/ytdl_sub/cli/main_args_parser.py +++ b/src/ytdl_sub/cli/main_args_parser.py @@ -71,42 +71,59 @@ class MainArguments: return None +################################################################################################### +# SHARED OPTIONS +def _add_shared_arguments(arg_parser: argparse.ArgumentParser, suppress_defaults: bool) -> None: + """ + Add shared arguments to sub parsers + + Parameters + ---------- + arg_parser + The parser to add shared args to + suppress_defaults + bool. Suppress sub parser defaults so they do not override the defaults in the parent parser + """ + arg_parser.add_argument( + MainArguments.CONFIG.short, + MainArguments.CONFIG.long, + metavar="CONFIGPATH", + type=str, + help="path to the config yaml, uses config.yaml if not provided", + default=argparse.SUPPRESS if suppress_defaults else "config.yaml", + ) + arg_parser.add_argument( + MainArguments.DRY_RUN.short, + MainArguments.DRY_RUN.long, + action="store_true", + help="preview what a download would output, " + "does not perform any video downloads or writes to output directories", + ) + arg_parser.add_argument( + MainArguments.LOG_LEVEL.short, + MainArguments.LOG_LEVEL.long, + metavar="|".join(LoggerLevels.names()), + type=str, + help="level of logs to print to console, defaults to info", + default=argparse.SUPPRESS if suppress_defaults else LoggerLevels.INFO.name, + choices=LoggerLevels.names(), + dest="ytdl_sub_log_level", + ) + + ################################################################################################### # GLOBAL PARSER parser = argparse.ArgumentParser( - description="ytdl-sub: Automate download and adding metadata with YoutubeDL" + description="ytdl-sub: Automate download and adding metadata with YoutubeDL", ) parser.add_argument("--version", action="version", version="%(prog)s " + __local_version__) -parser.add_argument( - MainArguments.CONFIG.short, - MainArguments.CONFIG.long, - metavar="CONFIGPATH", - type=str, - help="path to the config yaml, uses config.yaml if not provided", - default="config.yaml", -) -parser.add_argument( - MainArguments.DRY_RUN.short, - MainArguments.DRY_RUN.long, - action="store_true", - help="preview what a download would output, " - "does not perform any video downloads or writes to output directories", -) -parser.add_argument( - MainArguments.LOG_LEVEL.short, - MainArguments.LOG_LEVEL.long, - metavar="|".join(LoggerLevels.names()), - type=str, - help="level of logs to print to console, defaults to info", - default=LoggerLevels.INFO.name, - choices=LoggerLevels.names(), - dest="ytdl_sub_log_level", -) +_add_shared_arguments(parser, suppress_defaults=False) subparsers = parser.add_subparsers(dest="subparser") ################################################################################################### # SUBSCRIPTION PARSER subscription_parser = subparsers.add_parser("sub") +_add_shared_arguments(subscription_parser, suppress_defaults=True) subscription_parser.add_argument( "subscription_paths", metavar="SUBPATH", @@ -135,6 +152,7 @@ class ViewArgs(Enum): view_parser = subparsers.add_parser("view") +_add_shared_arguments(view_parser, suppress_defaults=True) view_parser.add_argument( "-sc", ViewArgs.SPLIT_CHAPTERS.value, diff --git a/tests/unit/cli/test_download_args_parser.py b/tests/unit/cli/test_download_args_parser.py index 149397b4..bb03d090 100644 --- a/tests/unit/cli/test_download_args_parser.py +++ b/tests/unit/cli/test_download_args_parser.py @@ -151,7 +151,7 @@ class TestDownloadArgsParser: extra_arguments=extra_args, config_options=config_options ).to_subscription_dict() - @pytest.mark.parametrize("main_argument", MainArguments.all()) + @pytest.mark.parametrize("main_argument", MainArguments.all_arguments()) def test_error_uses_main_args(self, main_argument, config_options_generator): config_options = config_options_generator() extra_args = _get_extra_arguments(cmd_string=f"dl {main_argument}") diff --git a/tests/unit/cli/test_main.py b/tests/unit/cli/test_main.py new file mode 100644 index 00000000..f7e700d8 --- /dev/null +++ b/tests/unit/cli/test_main.py @@ -0,0 +1,21 @@ +import sys +from unittest.mock import patch + +import pytest + +from ytdl_sub.cli.main import main +from ytdl_sub.utils.exceptions import ValidationException + + +def test_args_after_sub_work(): + with patch.object( + sys, + "argv", + ["ytdl-sub", "-c", "examples/tv_show_config.yaml", "sub", "--log-level", "debug"], + ), patch("ytdl_sub.cli.main._download_subscriptions_from_yaml_files") as mock_sub: + main() + + assert mock_sub.call_count == 1 + assert mock_sub.call_args.kwargs["args"].config == "examples/tv_show_config.yaml" + assert mock_sub.call_args.kwargs["args"].subscription_paths == ["subscriptions.yaml"] + assert mock_sub.call_args.kwargs["args"].ytdl_sub_log_level == "debug"