#!/usr/bin/env python3 import sys import argparse # Import the functions that define and execute the logic for each subcommand from .list_formats_tool import add_list_formats_parser, main_list_formats from .get_info_tool import add_get_info_parser, main_get_info from .download_tool import add_download_parser, main_download from .stress_policy_tool import add_stress_policy_parser, main_stress_policy from .stress_formats_tool import add_stress_formats_parser, main_stress_formats from .cookie_tool import add_cookie_tool_parser, main_cookie_tool from .download_aria_tool import add_download_aria_parser, main_download_aria from .download_native_py_tool import add_download_native_py_parser, main_download_native_py def main(): """ Main entry point for the yt-ops-client CLI. Parses arguments and dispatches to the appropriate subcommand function. """ # Workaround for argparse behavior with positional arguments that start with a hyphen. # If the command is 'get-info' and the last argument looks like a video ID # starting with a '-', we insert '--' before it to tell argparse to treat it # as a positional argument, not an option. This assumes the URL is the last argument. if len(sys.argv) >= 3 and sys.argv[1] == 'get-info': last_arg = sys.argv[-1] # A YouTube video ID is 11 characters. if last_arg.startswith('-') and len(last_arg) == 11: import re if re.fullmatch(r'-[a-zA-Z0-9_-]{10}', last_arg): sys.argv.insert(len(sys.argv) - 1, '--') parser = argparse.ArgumentParser( description="YT Ops Client Tools", formatter_class=argparse.RawTextHelpFormatter ) subparsers = parser.add_subparsers(dest='command', help='Available sub-commands') # Add subparsers from each tool module add_list_formats_parser(subparsers) add_get_info_parser(subparsers) # Create a top-level 'download' command with its own subcommands download_parser = subparsers.add_parser( 'download', help='Download using different methods.', description='Provides access to various download tools. Use "download --help" for details.' ) download_subparsers = download_parser.add_subparsers(dest='download_command', help='Available downloaders', required=True) add_download_parser(download_subparsers) # Adds 'cli' subcommand add_download_native_py_parser(download_subparsers) # Adds 'py' subcommand add_download_aria_parser(download_subparsers) # Adds 'aria-rpc' subcommand add_stress_policy_parser(subparsers) add_stress_formats_parser(subparsers) add_cookie_tool_parser(subparsers) args = parser.parse_args() # If no command is provided, print help and exit. if not args.command: parser.print_help() return 1 # Dispatch to the correct main function based on the command if args.command == 'list-formats': return main_list_formats(args) elif args.command == 'get-info': return main_get_info(args) elif args.command == 'download': if args.download_command == 'cli': return main_download(args) elif args.download_command == 'py': return main_download_native_py(args) elif args.download_command == 'aria-rpc': return main_download_aria(args) elif args.command == 'stress-policy': return main_stress_policy(args) elif args.command == 'stress-formats': return main_stress_formats(args) elif args.command == 'convert-cookies': return main_cookie_tool(args) # This path should not be reachable if a command is required or handled above. parser.print_help() return 1 if __name__ == "__main__": sys.exit(main())