From 481559e351ea782d4ceb164a9e2a78b9f6ca0a0b Mon Sep 17 00:00:00 2001 From: Silencer5179 <162629865+Silencer5179@users.noreply.github.com> Date: Fri, 8 Mar 2024 04:06:17 +0000 Subject: [PATCH] add optional vim keybindings (#840) --- cyberdrop_dl/managers/args_manager.py | 4 +- cyberdrop_dl/managers/manager.py | 2 + cyberdrop_dl/ui/prompts/general_prompts.py | 18 ++++-- .../settings_authentication_prompts.py | 30 +++++++-- .../ui/prompts/settings_global_prompts.py | 30 +++++++-- .../ui/prompts/settings_user_prompts.py | 62 ++++++++++++++----- cyberdrop_dl/ui/prompts/url_file_prompts.py | 6 +- cyberdrop_dl/ui/ui.py | 20 +++--- cyberdrop_dl/utils/args/args.py | 1 + cyberdrop_dl/utils/args/config_definitions.py | 1 + 10 files changed, 130 insertions(+), 44 deletions(-) diff --git a/cyberdrop_dl/managers/args_manager.py b/cyberdrop_dl/managers/args_manager.py index 6405ecab0..e00ded6ee 100644 --- a/cyberdrop_dl/managers/args_manager.py +++ b/cyberdrop_dl/managers/args_manager.py @@ -19,6 +19,7 @@ def __init__(self): self.no_ui = False self.load_config_from_args = False self.load_config_name = "" + self.vi_mode = None self.other_links: list = [] @@ -38,7 +39,8 @@ def startup(self) -> None: self.immediate_download = self.parsed_args['download'] self.load_config_name = self.parsed_args['config'] - + self.vi_mode = self.parsed_args['vi_mode'] + if self.parsed_args['no_ui']: self.immediate_download = True self.no_ui = True diff --git a/cyberdrop_dl/managers/manager.py b/cyberdrop_dl/managers/manager.py index 4066000f8..25741e7e7 100644 --- a/cyberdrop_dl/managers/manager.py +++ b/cyberdrop_dl/managers/manager.py @@ -39,6 +39,7 @@ def __init__(self): self.task_group: asyncio.TaskGroup = field(init=False) self.task_list: list = [] self.scrape_mapper = field(init=False) + self.vi_mode: bool = None def startup(self) -> None: """Startup process for the manager""" @@ -53,6 +54,7 @@ def startup(self) -> None: self.cache_manager.startup(self.path_manager.cache_dir / "cache.yaml") self.config_manager = ConfigManager(self) self.config_manager.startup() + self.vi_mode = self.config_manager.global_settings_data['General']['vi_mode'] if self.args_manager.vi_mode == None else self.args_manager.vi_mode self.path_manager.startup() self.log_manager = LogManager(self) diff --git a/cyberdrop_dl/ui/prompts/general_prompts.py b/cyberdrop_dl/ui/prompts/general_prompts.py index 4ae14998c..5a1d6a2d9 100644 --- a/cyberdrop_dl/ui/prompts/general_prompts.py +++ b/cyberdrop_dl/ui/prompts/general_prompts.py @@ -39,12 +39,13 @@ def main_prompt(manager: Manager) -> int: Choice(9, "Donate"), Choice(10, "Exit"), ], long_instruction="ARROW KEYS: Navigate | ENTER: Select", + vi_mode=manager.vi_mode, ).execute() return action -def manage_configs_prompt() -> int: +def manage_configs_prompt(manager: Manager) -> int: """Manage Configs Prompt""" console.clear() action = inquirer.select( @@ -59,12 +60,13 @@ def manage_configs_prompt() -> int: Choice(6, "Edit Global Values"), Choice(7, "Done"), ], long_instruction="ARROW KEYS: Navigate | ENTER: Select", + vi_mode=manager.vi_mode, ).execute() return action -def select_config_prompt(configs: List) -> str: +def select_config_prompt(manager: Manager, configs: List) -> str: """Select a config file from a list of configs""" choice = inquirer.fuzzy( choices=configs, @@ -73,6 +75,7 @@ def select_config_prompt(configs: List) -> str: invalid_message="Need to select a config.", message="Select a config file:", long_instruction="ARROW KEYS: Navigate | TYPE: Filter | TAB: select, ENTER: Finish Selection", + vi_mode=manager.vi_mode, ).execute() return choice @@ -89,14 +92,16 @@ def import_cyberdrop_v4_items_prompt(manager: Manager) -> None: Choice(1, "Import Config"), Choice(2, "Import download_history.sql"), Choice(3, "Done"), - ], long_instruction="ARROW KEYS: Navigate | ENTER: Select" + ], long_instruction="ARROW KEYS: Navigate | ENTER: Select", + vi_mode=manager.vi_mode, ).execute() # Import Config if action == 1: new_config_name = inquirer.text( message="What should this config be called?", - validate=EmptyInputValidator("Input should not be empty") + validate=EmptyInputValidator("Input should not be empty"), + vi_mode=manager.vi_mode, ).execute() if (manager.path_manager.config_dir / new_config_name).is_dir(): @@ -120,6 +125,7 @@ def import_cyberdrop_v4_items_prompt(manager: Manager) -> None: message="Select the download_history.sql file to import", default=home_path, validate=PathValidator(is_file=True, message="Input is not a file"), + vi_mode=manager.vi_mode, ).execute() transfer_v4_db(import_download_history_path, manager.path_manager.history_db) @@ -129,7 +135,7 @@ def import_cyberdrop_v4_items_prompt(manager: Manager) -> None: break -def donations_prompt() -> None: +def donations_prompt(manager: Manager) -> None: """Donations prompt""" console.clear() console.print("[bold]Donations[/bold]") @@ -147,4 +153,4 @@ def donations_prompt() -> None: console.print("") console.print("Thank you for your support!") console.print("") - inquirer.confirm(message="Press enter to return to the main menu.").execute() + inquirer.confirm(message="Press enter to return to the main menu.", vi_mode=manager.vi_mode).execute() diff --git a/cyberdrop_dl/ui/prompts/settings_authentication_prompts.py b/cyberdrop_dl/ui/prompts/settings_authentication_prompts.py index de5402316..fff8171da 100644 --- a/cyberdrop_dl/ui/prompts/settings_authentication_prompts.py +++ b/cyberdrop_dl/ui/prompts/settings_authentication_prompts.py @@ -34,7 +34,8 @@ def edit_authentication_values_prompt(manager: Manager) -> None: Choice(5, "Edit Imgur Client ID"), Choice(6, "Edit PixelDrain API Key"), Choice(7, "Done"), - ], long_instruction="ARROW KEYS: Navigate | ENTER: Select" + ], long_instruction="ARROW KEYS: Navigate | ENTER: Select", + vi_mode=manager.vi_mode, ).execute() # Edit Forums @@ -56,6 +57,7 @@ def edit_authentication_values_prompt(manager: Manager) -> None: message="Enter the GoFile API Key:", default=auth["GoFile"]["gofile_api_key"], long_instruction="You can get your premium GoFile API Key from https://gofile.io/myProfile", + vi_mode=manager.vi_mode, ).execute() auth["GoFile"]["gofile_api_key"] = gofile_api_key @@ -66,7 +68,8 @@ def edit_authentication_values_prompt(manager: Manager) -> None: message="Enter the Imgur Client ID:", default=auth["Imgur"]["imgur_client_id"], long_instruction="You can create an app and get your client ID " - "from https://imgur.com/account/settings/apps" + "from https://imgur.com/account/settings/apps", + vi_mode=manager.vi_mode, ).execute() auth["Imgur"]["imgur_client_id"] = imgur_client_id @@ -76,7 +79,8 @@ def edit_authentication_values_prompt(manager: Manager) -> None: pixeldrain_api_key = inquirer.text( message="Enter the PixelDrain API Key:", default=auth["PixelDrain"]["pixeldrain_api_key"], - long_instruction="You can get your premium API Key from https://pixeldrain.com/user/api_keys" + long_instruction="You can get your premium API Key from https://pixeldrain.com/user/api_keys", + vi_mode=manager.vi_mode, ).execute() auth["PixelDrain"]["pixeldrain_api_key"] = pixeldrain_api_key @@ -97,7 +101,8 @@ def edit_forum_authentication_values_prompt(manager: Manager) -> None: Choice(1, "Browser Cookie Extraction"), Choice(2, "Enter Cookie Values Manually"), Choice(3, "Done"), - ], long_instruction="ARROW KEYS: Navigate | ENTER: Select" + ], long_instruction="ARROW KEYS: Navigate | ENTER: Select", + vi_mode=manager.vi_mode, ).execute() # Browser Cookie Extraction @@ -112,7 +117,8 @@ def edit_forum_authentication_values_prompt(manager: Manager) -> None: Choice("opera", "Opera"), Choice("brave", "Brave"), Choice(1, "Done"), - ], long_instruction="ARROW KEYS: Navigate | ENTER: Select" + ], long_instruction="ARROW KEYS: Navigate | ENTER: Select", + vi_mode=manager.vi_mode, ).execute() # Done @@ -139,64 +145,78 @@ def edit_forum_authentication_values_prompt(manager: Manager) -> None: celebforum_username = inquirer.text( message="Enter your CelebForum Username:", default=manager.config_manager.authentication_data["Forums"]["celebforum_username"], + vi_mode=manager.vi_mode, ).execute() celebforum_password = inquirer.text( message="Enter your CelebForum Password:", default=manager.config_manager.authentication_data["Forums"]["celebforum_password"], + vi_mode=manager.vi_mode, ).execute() f95zone_username = inquirer.text( message="Enter your F95Zone Username:", default=manager.config_manager.authentication_data["Forums"]["f95zone_username"], + vi_mode=manager.vi_mode, ).execute() f95zone_password = inquirer.text( message="Enter your F95Zone Password:", default=manager.config_manager.authentication_data["Forums"]["f95zone_password"], + vi_mode=manager.vi_mode, ).execute() leakedmodels_username = inquirer.text( message="Enter your LeakedModels Username:", default=manager.config_manager.authentication_data["Forums"]["leakedmodels_username"], + vi_mode=manager.vi_mode, ).execute() leakedmodels_password = inquirer.text( message="Enter your LeakedModels Password:", default=manager.config_manager.authentication_data["Forums"]["leakedmodels_password"], + vi_mode=manager.vi_mode, ).execute() nudostar_username = inquirer.text( message="Enter your NudoStar Username:", default=manager.config_manager.authentication_data["Forums"]["nudostar_username"], + vi_mode=manager.vi_mode, ).execute() nudostar_password = inquirer.text( message="Enter your NudoStar Password:", default=manager.config_manager.authentication_data["Forums"]["nudostar_password"], + vi_mode=manager.vi_mode, ).execute() simpcity_username = inquirer.text( message="Enter your SimpCity Username:", default=manager.config_manager.authentication_data["Forums"]["simpcity_username"], + vi_mode=manager.vi_mode, ).execute() simpcity_password = inquirer.text( message="Enter your SimpCity Password:", default=manager.config_manager.authentication_data["Forums"]["simpcity_password"], + vi_mode=manager.vi_mode, ).execute() socialmediagirls_username = inquirer.text( message="Enter your SocialMediaGirls Username:", default=manager.config_manager.authentication_data["Forums"]["socialmediagirls_username"], + vi_mode=manager.vi_mode, ).execute() socialmediagirls_password = inquirer.text( message="Enter your SocialMediaGirls Password:", default=manager.config_manager.authentication_data["Forums"]["socialmediagirls_password"], + vi_mode=manager.vi_mode, ).execute() xbunker_username = inquirer.text( message="Enter your XBunker Username:", default=manager.config_manager.authentication_data["Forums"]["xbunker_username"], + vi_mode=manager.vi_mode, ).execute() xbunker_password = inquirer.text( message="Enter your XBunker Password:", default=manager.config_manager.authentication_data["Forums"]["xbunker_password"], + vi_mode=manager.vi_mode, ).execute() manager.config_manager.authentication_data["Forums"]["celebforum_username"] = celebforum_username diff --git a/cyberdrop_dl/ui/prompts/settings_global_prompts.py b/cyberdrop_dl/ui/prompts/settings_global_prompts.py index f2567cab6..2df0ffc7b 100644 --- a/cyberdrop_dl/ui/prompts/settings_global_prompts.py +++ b/cyberdrop_dl/ui/prompts/settings_global_prompts.py @@ -25,6 +25,7 @@ def edit_global_settings_prompt(manager: Manager) -> None: Choice(2, "Edit Rate Limiting Settings"), Choice(3, "Done"), ], + vi_mode=manager.vi_mode, ).execute() # Edit General Settings @@ -45,34 +46,45 @@ def edit_general_settings_prompt(manager: Manager) -> None: """Edit the general settings""" console.clear() console.print("Editing General Settings") - allow_insecure_connections = inquirer.confirm("Allow insecure connections?").execute() + allow_insecure_connections = inquirer.confirm("Allow insecure connections?", vi_mode=manager.vi_mode).execute() user_agent = inquirer.text( message="User Agent:", default=manager.config_manager.global_settings_data['General']['user_agent'], - validate=EmptyInputValidator("Input should not be empty") + validate=EmptyInputValidator("Input should not be empty"), + vi_mode=manager.vi_mode, ).execute() proxy = inquirer.text( message="Proxy:", - default=manager.config_manager.global_settings_data['General']['proxy'] + default=manager.config_manager.global_settings_data['General']['proxy'], + vi_mode=manager.vi_mode, ).execute() flaresolverr = inquirer.text( message="FlareSolverr (IP:PORT):", - default=manager.config_manager.global_settings_data['General']['flaresolverr'] + default=manager.config_manager.global_settings_data['General']['flaresolverr'], + vi_mode=manager.vi_mode, ).execute() max_filename_length = inquirer.number( message="Max Filename Length:", default=int(manager.config_manager.global_settings_data['General']['max_file_name_length']), float_allowed=False, + vi_mode=manager.vi_mode, ).execute() max_folder_name_length = inquirer.number( message="Max Folder Name Length:", default=int(manager.config_manager.global_settings_data['General']['max_folder_name_length']), float_allowed=False, + vi_mode=manager.vi_mode, ).execute() required_free_space = inquirer.number( message="Required Free Space (in GB):", default=int(manager.config_manager.global_settings_data['General']['required_free_space']), float_allowed=False, + vi_mode=manager.vi_mode, + ).execute() + manager.vi_mode = inquirer.confirm( + message="Enable VI/VIM keybindings?", + default=bool(manager.config_manager.global_settings_data['General']['vi_mode']), + vi_mode=manager.vi_mode, ).execute() manager.config_manager.global_settings_data['General']['allow_insecure_connections'] = allow_insecure_connections @@ -82,7 +94,7 @@ def edit_general_settings_prompt(manager: Manager) -> None: manager.config_manager.global_settings_data['General']['max_filename_length'] = int(max_filename_length) manager.config_manager.global_settings_data['General']['max_folder_name_length'] = int(max_folder_name_length) manager.config_manager.global_settings_data['General']['required_free_space'] = int(required_free_space) - + manager.config_manager.global_settings_data['General']['vi_mode'] = manager.vi_mode def edit_progress_settings_prompt(manager: Manager) -> None: """Edit the progress settings""" @@ -92,6 +104,7 @@ def edit_progress_settings_prompt(manager: Manager) -> None: message="Refresh Rate:", default=int(manager.config_manager.global_settings_data['Progress_Options']['refresh_rate']), float_allowed=False, + vi_mode=manager.vi_mode, ).execute() manager.config_manager.global_settings_data['Progress_Options']['refresh_rate'] = int(refresh_rate) @@ -105,37 +118,44 @@ def edit_rate_limiting_settings_prompt(manager: Manager) -> None: message="Connection Timeout (in seconds):", default=int(manager.config_manager.global_settings_data['Rate_Limiting_Options']['connection_timeout']), float_allowed=False, + vi_mode=manager.vi_mode, ).execute() read_timeout = inquirer.number( message="Read Timeout (in seconds):", default=int(manager.config_manager.global_settings_data['Rate_Limiting_Options']['read_timeout']), float_allowed=False, + vi_mode=manager.vi_mode, ).execute() download_attempts = inquirer.number( message="Download Attempts:", default=int(manager.config_manager.global_settings_data['Rate_Limiting_Options']['download_attempts']), float_allowed=False, + vi_mode=manager.vi_mode, ).execute() rate_limit = inquirer.number( message="Maximum number of requests per second:", default=int(manager.config_manager.global_settings_data['Rate_Limiting_Options']['rate_limit']), float_allowed=False, + vi_mode=manager.vi_mode, ).execute() throttle = inquirer.number( message="Delay between requests during the download stage:", default=float(manager.config_manager.global_settings_data['Rate_Limiting_Options']['download_delay']), float_allowed=True, + vi_mode=manager.vi_mode, ).execute() max_simultaneous_downloads = inquirer.number( message="Maximum number of simultaneous downloads:", default=int(manager.config_manager.global_settings_data['Rate_Limiting_Options']['max_simultaneous_downloads']), float_allowed=False, + vi_mode=manager.vi_mode, ).execute() max_simultaneous_downloads_per_domain = inquirer.number( message="Maximum number of simultaneous downloads per domain:", default=int(manager.config_manager.global_settings_data['Rate_Limiting_Options']['max_simultaneous_downloads_per_domain']), float_allowed=False, + vi_mode=manager.vi_mode, ).execute() manager.config_manager.global_settings_data['Rate_Limiting_Options']['connection_timeout'] = int(connection_timeout) diff --git a/cyberdrop_dl/ui/prompts/settings_user_prompts.py b/cyberdrop_dl/ui/prompts/settings_user_prompts.py index e63df7795..39c78cb00 100644 --- a/cyberdrop_dl/ui/prompts/settings_user_prompts.py +++ b/cyberdrop_dl/ui/prompts/settings_user_prompts.py @@ -24,7 +24,8 @@ def create_new_config_prompt(manager: Manager) -> None: console.print("Create a new config file") config_name = inquirer.text( message="Enter the name of the config:", - validate=EmptyInputValidator("Input should not be empty") + validate=EmptyInputValidator("Input should not be empty"), + vi_mode=manager.vi_mode, ).execute() if (manager.path_manager.config_dir / config_name).is_dir(): console.print(f"Config with name '{config_name}' already exists!") @@ -52,7 +53,8 @@ def edit_config_values_prompt(manager: Manager) -> None: Choice(6, "Edit Runtime Options"), Choice(7, "Edit Sorting Options"), Choice(8, "Done"), - ], long_instruction="ARROW KEYS: Navigate | ENTER: Select" + ], long_instruction="ARROW KEYS: Navigate | ENTER: Select", + vi_mode=manager.vi_mode, ).execute() # Edit Download Options @@ -126,7 +128,8 @@ def edit_download_options_prompt(config: Dict) -> None: Choice(value="skip_download_mark_completed", name="Skip Download and Mark it as Completed", enabled=config["Download_Options"]["skip_download_mark_completed"]), - ], long_instruction="ARROW KEYS: Navigate | TAB: Select | ENTER: Confirm" + ], long_instruction="ARROW KEYS: Navigate | TAB: Select | ENTER: Confirm", + vi_mode=manager.vi_mode, ).execute() for key in config["Download_Options"]: @@ -143,12 +146,14 @@ def edit_input_output_file_paths_prompt(config: Dict) -> None: input_file = inquirer.filepath( message="Enter the input file path:", default=str(config['Files']['input_file']), - validate=PathValidator(is_file=True, message="Input is not a file") + validate=PathValidator(is_file=True, message="Input is not a file"), + vi_mode=manager.vi_mode, ).execute() download_folder = inquirer.text( message="Enter the download folder path:", default=str(config['Files']['download_folder']), - validate=PathValidator(is_dir=True, message="Input is not a directory") + validate=PathValidator(is_dir=True, message="Input is not a directory"), + vi_mode=manager.vi_mode, ).execute() config['Files']['input_file'] = Path(input_file) @@ -162,32 +167,38 @@ def edit_log_file_naming_path_prompt(config: Dict) -> None: log_folder = inquirer.filepath( message="Enter the log folder path:", default=str(config['Logs']['log_folder']), - validate=PathValidator(is_dir=True, message="Input is not a directory") + validate=PathValidator(is_dir=True, message="Input is not a directory"), + vi_mode=manager.vi_mode, ).execute() main_log_filename = inquirer.text( message="Enter the main log file name:", default=config['Logs']['main_log_filename'], - validate=EmptyInputValidator("Input should not be empty") + validate=EmptyInputValidator("Input should not be empty"), + vi_mode=manager.vi_mode, ).execute() last_forum_post_filename = inquirer.text( message="Enter the last forum post log file name:", default=config['Logs']['last_forum_post_filename'], - validate=EmptyInputValidator("Input should not be empty") + validate=EmptyInputValidator("Input should not be empty"), + vi_mode=manager.vi_mode, ).execute() unsupported_urls_filename = inquirer.text( message="Enter the unsupported urls log file name:", default=config['Logs']['unsupported_urls_filename'], - validate=EmptyInputValidator("Input should not be empty") + validate=EmptyInputValidator("Input should not be empty"), + vi_mode=manager.vi_mode, ).execute() download_error_urls_filename = inquirer.text( message="Enter the download error urls log file name:", default=config['Logs']['download_error_urls_filename'], - validate=EmptyInputValidator("Input should not be empty") + validate=EmptyInputValidator("Input should not be empty"), + vi_mode=manager.vi_mode, ).execute() scrape_error_urls_filename = inquirer.text( message="Enter the scrape error urls log file name:", default=config['Logs']['scrape_error_urls_filename'], - validate=EmptyInputValidator("Input should not be empty") + validate=EmptyInputValidator("Input should not be empty"), + vi_mode=manager.vi_mode, ).execute() config['Logs']['log_folder'] = Path(log_folder) @@ -207,36 +218,42 @@ def edit_file_size_limits_prompt(config: Dict) -> None: default=int(config['File_Size_Limits']['maximum_image_size']), validate=NumberValidator(), long_instruction="This value is in bytes (0 is no limit)", + vi_mode=manager.vi_mode, ).execute() maximum_video_size = inquirer.number( message="Enter the maximum video size:", default=int(config['File_Size_Limits']['maximum_video_size']), validate=NumberValidator(), long_instruction="This value is in bytes (0 is no limit)", + vi_mode=manager.vi_mode, ).execute() maximum_other_size = inquirer.number( message="Enter the maximum other file type size:", default=int(config['File_Size_Limits']['maximum_other_size']), validate=NumberValidator(), long_instruction="This value is in bytes (0 is no limit)", + vi_mode=manager.vi_mode, ).execute() minimum_image_size = inquirer.number( message="Enter the minimum image size:", default=int(config['File_Size_Limits']['minimum_image_size']), validate=NumberValidator(), long_instruction="This value is in bytes (0 is no limit)", + vi_mode=manager.vi_mode, ).execute() minimum_video_size = inquirer.number( message="Enter the minimum video size:", default=int(config['File_Size_Limits']['minimum_video_size']), validate=NumberValidator(), long_instruction="This value is in bytes (0 is no limit)", + vi_mode=manager.vi_mode, ).execute() minimum_other_size = inquirer.number( message="Enter the minimum other file type size:", default=int(config['File_Size_Limits']['minimum_other_size']), validate=NumberValidator(), long_instruction="This value is in bytes (0 is no limit)", + vi_mode=manager.vi_mode, ).execute() config['File_Size_Limits']['maximum_image_size'] = int(maximum_image_size) @@ -270,6 +287,7 @@ def edit_ignore_options_prompt(config: Dict) -> None: name="Ignore coomer ads when scraping", enabled=config["Ignore_Options"]["ignore_coomer_ads"]), ], long_instruction="ARROW KEYS: Move | TAB: Select | ENTER: Confirm", + vi_mode=manager.vi_mode, ).execute() for key in config["Ignore_Options"]: @@ -285,6 +303,7 @@ def edit_ignore_options_prompt(config: Dict) -> None: multiselect=True, message="Select any sites you want to ignore while scraping:", long_instruction="ARROW KEYS: Move | TYPE: Filter | TAB: Select | ENTER: Confirm", + vi_mode=manager.vi_mode, ).execute() skip_hosts = [host for host in skip_hosts if host in SupportedDomains.supported_hosts] @@ -297,6 +316,7 @@ def edit_ignore_options_prompt(config: Dict) -> None: multiselect=True, message="Select only the sites you want to scrape from:", long_instruction="ARROW KEYS: Move | TYPE: Filter | TAB: Select | ENTER: Confirm", + vi_mode=manager.vi_mode, ).execute() only_hosts = [host for host in only_hosts if host in SupportedDomains.supported_hosts] @@ -326,6 +346,7 @@ def edit_runtime_options_prompt(config: Dict) -> None: name="Send unsupported urls to JDownloader to download", enabled=config["Runtime_Options"]["send_unsupported_to_jdownloader"]), ], long_instruction="ARROW KEYS: Move | TAB: Select | ENTER: Confirm", + vi_mode=manager.vi_mode, ).execute() log_level = inquirer.number( @@ -333,6 +354,7 @@ def edit_runtime_options_prompt(config: Dict) -> None: default=int(config['Runtime_Options']['log_level']), validate=NumberValidator(), long_instruction="10 is the default (uses pythons logging numerical levels)", + vi_mode=manager.vi_mode, ).execute() for key in config["Runtime_Options"]: @@ -349,38 +371,44 @@ def edit_sort_options_prompt(config: Dict) -> None: console.clear() console.print("Editing Sort Options") config["Sorting"]["sort_downloads"] = False - sort_downloads = inquirer.confirm(message="Do you want Cyberdrop-DL to sort files for you?").execute() + sort_downloads = inquirer.confirm(message="Do you want Cyberdrop-DL to sort files for you?", vi_mode=manager.vi_mode).execute() if sort_downloads: config["Sorting"]["sort_downloads"] = True sort_folder = inquirer.filepath( message="Enter the folder you want to sort files into:", default=str(config['Sorting']['sort_folder']), validate=PathValidator(is_dir=True, message="Input is not a directory"), + vi_mode=manager.vi_mode, ).execute() sort_incremementer_format = inquirer.text( message="Enter the sort incrementer format:", default=config['Sorting']['sort_incremementer_format'], - validate=EmptyInputValidator("Input should not be empty") + validate=EmptyInputValidator("Input should not be empty"), + vi_mode=manager.vi_mode, ).execute() sorted_audio = inquirer.text( message="Enter the format you want to sort audio files into:", default=config['Sorting']['sorted_audio'], - validate=EmptyInputValidator("Input should not be empty") + validate=EmptyInputValidator("Input should not be empty"), + vi_mode=manager.vi_mode, ).execute() sorted_video = inquirer.text( message="Enter the format you want to sort video files into:", default=config['Sorting']['sorted_video'], - validate=EmptyInputValidator("Input should not be empty") + validate=EmptyInputValidator("Input should not be empty"), + vi_mode=manager.vi_mode, ).execute() sorted_image = inquirer.text( message="Enter the format you want to sort image files into:", default=config['Sorting']['sorted_image'], - validate=EmptyInputValidator("Input should not be empty") + validate=EmptyInputValidator("Input should not be empty"), + vi_mode=manager.vi_mode, ).execute() sorted_other = inquirer.text( message="Enter the format you want to sort other files into:", default=config['Sorting']['sorted_other'], - validate=EmptyInputValidator("Input should not be empty") + validate=EmptyInputValidator("Input should not be empty"), + vi_mode=manager.vi_mode, ).execute() config['Sorting']['sort_folder'] = Path(sort_folder) diff --git a/cyberdrop_dl/ui/prompts/url_file_prompts.py b/cyberdrop_dl/ui/prompts/url_file_prompts.py index 0434c9514..dbf03a2f3 100644 --- a/cyberdrop_dl/ui/prompts/url_file_prompts.py +++ b/cyberdrop_dl/ui/prompts/url_file_prompts.py @@ -4,10 +4,9 @@ from InquirerPy import inquirer from rich.console import Console -console = Console() +console = Console() - -def edit_urls_prompt(URLs_File: Path, fix_strings=True) -> None: +def edit_urls_prompt(URlS_File: Path, vi_mode: bool, fix_strings=True) -> None: """Edit the URLs file""" console.clear() console.print(f"Editing URLs: {URLs_File}") @@ -17,6 +16,7 @@ def edit_urls_prompt(URLs_File: Path, fix_strings=True) -> None: result = inquirer.text( message="URLs:", multiline=True, default=existing_urls, long_instruction="Press escape and then enter to finish editing.", + vi_mode=vi_mode, ).execute() if fix_strings: diff --git a/cyberdrop_dl/ui/ui.py b/cyberdrop_dl/ui/ui.py index da8b841a7..a500d9d60 100644 --- a/cyberdrop_dl/ui/ui.py +++ b/cyberdrop_dl/ui/ui.py @@ -28,7 +28,9 @@ def program_ui(manager: Manager): console.clear() console.print(f"[bold]Cyberdrop Downloader (V{str(__version__)})[/bold]") console.print(f"[bold]Current Config:[/bold] {manager.config_manager.loaded_config}") - + + #vi_mode = manager.config_manager.settings_data['General']['input_file'] if not manager.args_manager.vi_mode else manager.args_manager.vi_mode + action = main_prompt(manager) # Download @@ -48,12 +50,12 @@ def program_ui(manager: Manager): # Edit URLs elif action == 4: input_file = manager.config_manager.settings_data['Files']['input_file'] if not manager.args_manager.input_file else manager.args_manager.input_file - edit_urls_prompt(input_file) + edit_urls_prompt(input_file, manager.vi_mode) # Select Config elif action == 5: configs = manager.config_manager.get_configs() - selected_config = select_config_prompt(configs) + selected_config = select_config_prompt(manager, configs) manager.config_manager.change_config(selected_config) elif action == 6: @@ -62,12 +64,14 @@ def program_ui(manager: Manager): input_file = inquirer.filepath( message="Enter the input file path:", default=str(manager.config_manager.settings_data['Files']['input_file']), - validate=PathValidator(is_file=True, message="Input is not a file") + validate=PathValidator(is_file=True, message="Input is not a file"), + vi_mode=manager.vi_mode, ).execute() download_folder = inquirer.text( message="Enter the download folder path:", default=str(manager.config_manager.settings_data['Files']['download_folder']), - validate=PathValidator(is_dir=True, message="Input is not a directory") + validate=PathValidator(is_dir=True, message="Input is not a directory"), + vi_mode=manager.vi_mode, ).execute() manager.config_manager.settings_data['Files']['input_file'] = Path(input_file) @@ -81,7 +85,7 @@ def program_ui(manager: Manager): console.print("[bold]Manage Configs[/bold]") console.print(f"[bold]Current Config:[/bold] {manager.config_manager.loaded_config}") - action = manage_configs_prompt() + action = manage_configs_prompt(manager) # Change Default Config if action == 1: @@ -102,6 +106,7 @@ def program_ui(manager: Manager): inquirer.confirm( message="You cannot delete the currently active config, press enter to continue.", default=False, + vi_mode=manager.vi_mode, ).execute() continue manager.config_manager.delete_config(selected_config) @@ -109,6 +114,7 @@ def program_ui(manager: Manager): inquirer.confirm( message="There is only one config, press enter to continue.", default=False, + vi_mode=manager.vi_mode, ).execute() # Edit Config @@ -133,7 +139,7 @@ def program_ui(manager: Manager): # Donate elif action == 9: - donations_prompt() + donations_prompt(manager) # Exit elif action == 10: diff --git a/cyberdrop_dl/utils/args/args.py b/cyberdrop_dl/utils/args/args.py index 874d67e96..4839ac19e 100644 --- a/cyberdrop_dl/utils/args/args.py +++ b/cyberdrop_dl/utils/args/args.py @@ -16,6 +16,7 @@ def parse_args() -> argparse.Namespace: general.add_argument("--download", action="store_true", help="Skip the UI and go straight to downloading", default=False) general.add_argument("--download-all-configs", action="store_true", help="Skip the UI and go straight to downloading (runs all configs sequentially)", default=False) general.add_argument("--retry-failed", action="store_true", help="retry failed downloads", default=False) + general.add_argument("--vi-mode", action="store_true", help="enable VIM keybindings for UI", default=None) # File Paths file_paths = parser.add_argument_group("File_Paths") diff --git a/cyberdrop_dl/utils/args/config_definitions.py b/cyberdrop_dl/utils/args/config_definitions.py index 379e79b79..625e34286 100644 --- a/cyberdrop_dl/utils/args/config_definitions.py +++ b/cyberdrop_dl/utils/args/config_definitions.py @@ -121,6 +121,7 @@ "max_file_name_length": 95, "max_folder_name_length": 60, "required_free_space": 5, + "vi_mode": False, }, "Rate_Limiting_Options": { "connection_timeout": 15,