[FEATURE] cli-to-sub argument to convert yt-dlp args to ytdl-sub (#1376)
Example usage: ``` $ ytdl-sub cli-to-sub -S vcodec:h264,res:480,acodec:m4a ytdl_options: format_sort: - vcodec:h264 - res:480 - acodec:m4a ```
This commit is contained in:
parent
c3ca3c6379
commit
ed55f3a3f7
5 changed files with 100 additions and 2 deletions
|
|
@ -105,3 +105,11 @@ Preview the source variables for a given URL. Helpful to create new subscription
|
|||
|
||||
-sc, --split-chapters
|
||||
View source variables after splitting by chapters
|
||||
|
||||
CLI to SUB Options
|
||||
------------------
|
||||
Convert yt-dlp cli arguments to ytdl-sub `ytdl_options` arguments.
|
||||
|
||||
.. code-block::
|
||||
|
||||
ytdl-sub cli-to-sub [YT-DLP ARGS]
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from yt_dlp.utils import sanitize_filename
|
|||
from ytdl_sub.cli.output_summary import output_summary
|
||||
from ytdl_sub.cli.output_transaction_log import _maybe_validate_transaction_log_file
|
||||
from ytdl_sub.cli.output_transaction_log import output_transaction_log
|
||||
from ytdl_sub.cli.parsers.cli_to_sub import print_cli_to_sub
|
||||
from ytdl_sub.cli.parsers.dl import DownloadArgsParser
|
||||
from ytdl_sub.cli.parsers.main import DEFAULT_CONFIG_FILE_NAME
|
||||
from ytdl_sub.cli.parsers.main import parser
|
||||
|
|
@ -206,6 +207,10 @@ def main() -> List[Subscription]:
|
|||
|
||||
args, extra_args = parser.parse_known_args()
|
||||
|
||||
if args.subparser == "cli-to-sub":
|
||||
print_cli_to_sub(args=extra_args)
|
||||
return []
|
||||
|
||||
# Load the config
|
||||
if args.config:
|
||||
config = ConfigFile.from_file_path(args.config)
|
||||
|
|
@ -263,7 +268,7 @@ def main() -> List[Subscription]:
|
|||
_view_url_from_cli(config=config, url=args.url, split_chapters=args.split_chapters)
|
||||
)
|
||||
else:
|
||||
raise ValidationException("Must provide one of the commands: sub, dl, view")
|
||||
raise ValidationException("Must provide one of the commands: sub, dl, view, cli-to-sub")
|
||||
|
||||
if not args.suppress_transaction_log:
|
||||
output_transaction_log(
|
||||
|
|
|
|||
64
src/ytdl_sub/cli/parsers/cli_to_sub.py
Normal file
64
src/ytdl_sub/cli/parsers/cli_to_sub.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
from typing import List
|
||||
|
||||
import yt_dlp
|
||||
import yt_dlp.options
|
||||
|
||||
from ytdl_sub.utils.logger import Logger
|
||||
from ytdl_sub.utils.yaml import dump_yaml
|
||||
|
||||
logger = Logger.get()
|
||||
|
||||
# pylint: disable=missing-function-docstring
|
||||
|
||||
##############################################################
|
||||
# --- BEGIN ----
|
||||
# Copy of https://github.com/yt-dlp/yt-dlp/blob/master/devscripts/cli_to_api.py
|
||||
|
||||
create_parser = yt_dlp.options.create_parser
|
||||
|
||||
|
||||
def parse_patched_options(opts):
|
||||
|
||||
patched_parser = create_parser()
|
||||
patched_parser.defaults.update(
|
||||
{
|
||||
"ignoreerrors": False,
|
||||
"retries": 0,
|
||||
"fragment_retries": 0,
|
||||
"extract_flat": False,
|
||||
"concat_playlist": "never",
|
||||
"update_self": False,
|
||||
}
|
||||
)
|
||||
yt_dlp.options.create_parser = lambda: patched_parser
|
||||
try:
|
||||
return yt_dlp.parse_options(opts)
|
||||
finally:
|
||||
yt_dlp.options.create_parser = create_parser
|
||||
|
||||
|
||||
default_opts = parse_patched_options([]).ydl_opts
|
||||
|
||||
|
||||
def cli_to_api(opts, cli_defaults=False):
|
||||
opts = (yt_dlp.parse_options if cli_defaults else parse_patched_options)(opts).ydl_opts
|
||||
|
||||
diff = {k: v for k, v in opts.items() if default_opts[k] != v}
|
||||
if "postprocessors" in diff:
|
||||
diff["postprocessors"] = [
|
||||
pp for pp in diff["postprocessors"] if pp not in default_opts["postprocessors"]
|
||||
]
|
||||
return diff
|
||||
|
||||
|
||||
# --- END ----
|
||||
##############################################################
|
||||
|
||||
|
||||
def print_cli_to_sub(args: List[str]) -> None:
|
||||
api_args = cli_to_api(args)
|
||||
if not api_args:
|
||||
logger.info("Does not resolve to any yt-dlp args")
|
||||
return
|
||||
|
||||
print(dump_yaml({"ytdl_options": api_args}))
|
||||
|
|
@ -221,3 +221,7 @@ view_parser.add_argument(
|
|||
help="View source variables after splitting by chapters",
|
||||
)
|
||||
view_parser.add_argument("url", help="URL to view source variables for")
|
||||
|
||||
###################################################################################################
|
||||
# CLI-TO-SUB PARSER
|
||||
cli_to_sub_parser = subparsers.add_parser("cli-to-sub")
|
||||
|
|
|
|||
|
|
@ -244,7 +244,9 @@ def test_no_positional_arg_command(mock_sys_exit, tv_show_config_path):
|
|||
main()
|
||||
|
||||
assert mock_error.call_count == 1
|
||||
assert mock_error.call_args.args[0] == "Must provide one of the commands: sub, dl, view"
|
||||
assert mock_error.call_args.args[0] == (
|
||||
"Must provide one of the commands: sub, dl, view, cli-to-sub"
|
||||
)
|
||||
|
||||
|
||||
def test_bad_config_path(mock_sys_exit):
|
||||
|
|
@ -264,3 +266,18 @@ def test_bad_config_path(mock_sys_exit):
|
|||
"The config file 'does_not_exist.yaml' could not be found. "
|
||||
"Did you set --config correctly?"
|
||||
)
|
||||
|
||||
|
||||
def test_cli_to_sub(mock_sys_exit, capsys):
|
||||
with (
|
||||
mock_sys_exit(expected_exit_code=0),
|
||||
patch.object(
|
||||
sys,
|
||||
"argv",
|
||||
["ytdl-sub", "cli-to-sub", "--mark-watched", "--mtime"],
|
||||
),
|
||||
):
|
||||
main()
|
||||
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == ("ytdl_options:\n mark_watched: true\n updatetime: true\n\n")
|
||||
|
|
|
|||
Loading…
Reference in a new issue