[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
|
-sc, --split-chapters
|
||||||
View source variables after splitting by 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_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 _maybe_validate_transaction_log_file
|
||||||
from ytdl_sub.cli.output_transaction_log import output_transaction_log
|
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.dl import DownloadArgsParser
|
||||||
from ytdl_sub.cli.parsers.main import DEFAULT_CONFIG_FILE_NAME
|
from ytdl_sub.cli.parsers.main import DEFAULT_CONFIG_FILE_NAME
|
||||||
from ytdl_sub.cli.parsers.main import parser
|
from ytdl_sub.cli.parsers.main import parser
|
||||||
|
|
@ -206,6 +207,10 @@ def main() -> List[Subscription]:
|
||||||
|
|
||||||
args, extra_args = parser.parse_known_args()
|
args, extra_args = parser.parse_known_args()
|
||||||
|
|
||||||
|
if args.subparser == "cli-to-sub":
|
||||||
|
print_cli_to_sub(args=extra_args)
|
||||||
|
return []
|
||||||
|
|
||||||
# Load the config
|
# Load the config
|
||||||
if args.config:
|
if args.config:
|
||||||
config = ConfigFile.from_file_path(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)
|
_view_url_from_cli(config=config, url=args.url, split_chapters=args.split_chapters)
|
||||||
)
|
)
|
||||||
else:
|
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:
|
if not args.suppress_transaction_log:
|
||||||
output_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",
|
help="View source variables after splitting by chapters",
|
||||||
)
|
)
|
||||||
view_parser.add_argument("url", help="URL to view source variables for")
|
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()
|
main()
|
||||||
|
|
||||||
assert mock_error.call_count == 1
|
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):
|
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. "
|
"The config file 'does_not_exist.yaml' could not be found. "
|
||||||
"Did you set --config correctly?"
|
"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