From bd152be4e85c90282361324e6c4cf6db5d6ea472 Mon Sep 17 00:00:00 2001 From: Nigel1992 Date: Sun, 30 Mar 2025 22:14:03 +0200 Subject: [PATCH 1/3] fix: improve Linux path handling and fix permission issues --- config.py | 77 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 28 deletions(-) diff --git a/config.py b/config.py index 2fb5954..1d8e6bf 100644 --- a/config.py +++ b/config.py @@ -85,28 +85,45 @@ def setup_config(translator=None): elif sys.platform == "linux": # Get the actual user's home directory, handling both sudo and normal cases - current_user = os.getenv('USER') or os.getenv('USERNAME') or os.getenv('SUDO_USER') + sudo_user = os.environ.get('SUDO_USER') + current_user = sudo_user if sudo_user else (os.getenv('USER') or os.getenv('USERNAME')) + if not current_user: current_user = os.path.expanduser('~').split('/')[-1] - actual_home = f"/home/{current_user}" + # Handle sudo case + if sudo_user: + actual_home = f"/home/{sudo_user}" + root_home = "/root" + else: + actual_home = f"/home/{current_user}" + root_home = None + if not os.path.exists(actual_home): actual_home = os.path.expanduser("~") # Define base config directory config_base = os.path.join(actual_home, ".config") - # Try both "Cursor" and "cursor" directory names + # Try both "Cursor" and "cursor" directory names in both user and root locations cursor_dir = None - for dir_name in ["Cursor", "cursor"]: - test_dir = os.path.join(config_base, dir_name) - if os.path.exists(test_dir): - cursor_dir = test_dir + possible_paths = [ + os.path.join(config_base, "Cursor"), + os.path.join(config_base, "cursor"), + os.path.join(root_home, ".config", "Cursor") if root_home else None, + os.path.join(root_home, ".config", "cursor") if root_home else None + ] + + for path in possible_paths: + if path and os.path.exists(path): + cursor_dir = path break if not cursor_dir: - print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.neither_cursor_nor_cursor_directory_found', config_base=config_base)}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once')}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['WARNING']} Neither Cursor nor cursor directory found in {config_base}{Style.RESET_ALL}") + if root_home: + print(f"{Fore.YELLOW}{EMOJI['INFO']} Also checked {root_home}/.config{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} Please make sure Cursor is installed and has been run at least once{Style.RESET_ALL}") # Define Linux paths using the found cursor directory storage_path = os.path.abspath(os.path.join(cursor_dir, "User/globalStorage/storage.json")) if cursor_dir else "" @@ -116,46 +133,50 @@ def setup_config(translator=None): try: # Check storage directory if storage_dir and not os.path.exists(storage_dir): - print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_directory_not_found', storage_dir=storage_dir)}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once')}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['WARNING']} Storage directory not found: {storage_dir}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} Please make sure Cursor is installed and has been run at least once{Style.RESET_ALL}") # Check storage.json with more detailed verification if storage_path and os.path.exists(storage_path): # Get file stats try: stat = os.stat(storage_path) - print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.storage_file_found', storage_path=storage_path)}{Style.RESET_ALL}") - print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_size', stat.st_size)}{Style.RESET_ALL}") - print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_permissions', oct(stat.st_mode & 0o777))}{Style.RESET_ALL}") - print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_owner', stat.st_uid)}{Style.RESET_ALL}") - print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_group', stat.st_gid)}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['INFO']} Storage file found: {storage_path}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['INFO']} File size: {stat.st_size} bytes{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['INFO']} File permissions: {oct(stat.st_mode & 0o777)}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['INFO']} File owner: {stat.st_uid}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['INFO']} File group: {stat.st_gid}{Style.RESET_ALL}") except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_getting_file_stats', error=str(e))}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} Error getting file stats: {str(e)}{Style.RESET_ALL}") # Check if file is readable and writable if not os.access(storage_path, os.R_OK | os.W_OK): - print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.permission_denied', storage_path=storage_path)}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.try_running', current_user=current_user, storage_path=storage_path)}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.and', storage_path=storage_path)}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} Permission denied: {storage_path}{Style.RESET_ALL}") + if sudo_user: + print(f"{Fore.YELLOW}{EMOJI['INFO']} Try running: chown {sudo_user}:{sudo_user} {storage_path}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} And: chmod 644 {storage_path}{Style.RESET_ALL}") + else: + print(f"{Fore.YELLOW}{EMOJI['INFO']} Try running: chown {current_user}:{current_user} {storage_path}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} And: chmod 644 {storage_path}{Style.RESET_ALL}") # Try to read the file to verify it's not corrupted try: with open(storage_path, 'r') as f: content = f.read() if not content.strip(): - print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_file_is_empty', storage_path=storage_path)}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once')}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['WARNING']} Storage file is empty: {storage_path}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} Please make sure Cursor is installed and has been run at least once{Style.RESET_ALL}") else: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('config.storage_file_is_valid_and_contains_data')}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Storage file is valid and contains data{Style.RESET_ALL}") except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_reading_storage_file', error=str(e))}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.the_file_might_be_corrupted_please_reinstall_cursor')}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} Error reading storage file: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} The file might be corrupted. Please reinstall Cursor{Style.RESET_ALL}") elif storage_path: - print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_file_not_found', storage_path=storage_path)}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once')}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['WARNING']} Storage file not found: {storage_path}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} Please make sure Cursor is installed and has been run at least once{Style.RESET_ALL}") except (OSError, IOError) as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_checking_linux_paths', error=str(e))}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} Error checking Linux paths: {str(e)}{Style.RESET_ALL}") # Define all paths using the found cursor directory default_config['LinuxPaths'] = { From d7b056b3393c70600afe37ced29e339ef7ae3112 Mon Sep 17 00:00:00 2001 From: Nigel1992 Date: Sun, 30 Mar 2025 22:27:08 +0200 Subject: [PATCH 2/3] fix: improve Linux Chrome visibility and root user handling --- new_tempemail.py | 30 +++++++++++++++++++++++++--- oauth_auth.py | 51 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/new_tempemail.py b/new_tempemail.py index 307b301..dfb96b3 100644 --- a/new_tempemail.py +++ b/new_tempemail.py @@ -106,11 +106,31 @@ class NewTempEmail: # 创建浏览器选项 co = ChromiumOptions() - co.set_argument("--headless=new") + + # Only use headless for non-OAuth operations + if not hasattr(self, 'auth_type') or self.auth_type != 'oauth': + co.set_argument("--headless=new") if sys.platform == "linux": - co.set_argument("--no-sandbox") - + # Check if DISPLAY is set when not in headless mode + if not co.arguments.get("--headless=new") and not os.environ.get('DISPLAY'): + print(f"{Fore.RED}❌ No display found. Make sure X server is running.{Style.RESET_ALL}") + print(f"{Fore.YELLOW}ℹ️ Try: export DISPLAY=:0{Style.RESET_ALL}") + return False + + co.set_argument("--no-sandbox") + co.set_argument("--disable-dev-shm-usage") + co.set_argument("--disable-gpu") + + # If running as root, try to use actual user's Chrome profile + if os.geteuid() == 0: + sudo_user = os.environ.get('SUDO_USER') + if sudo_user: + actual_home = f"/home/{sudo_user}" + user_data_dir = os.path.join(actual_home, ".config", "google-chrome") + if os.path.exists(user_data_dir): + print(f"{Fore.CYAN}ℹ️ Using Chrome profile from: {user_data_dir}{Style.RESET_ALL}") + co.set_argument(f"--user-data-dir={user_data_dir}") co.auto_port() # 自动设置端口 @@ -132,6 +152,10 @@ class NewTempEmail: print(f"{Fore.RED}❌ {self.translator.get('email.browser_start_error')}: {str(e)}{Style.RESET_ALL}") else: print(f"{Fore.RED}❌ 启动浏览器失败: {str(e)}{Style.RESET_ALL}") + + if sys.platform == "linux": + print(f"{Fore.YELLOW}ℹ️ Make sure Chrome/Chromium is properly installed{Style.RESET_ALL}") + print(f"{Fore.YELLOW}ℹ️ Try: sudo apt install chromium-browser{Style.RESET_ALL}") return False def create_email(self): diff --git a/oauth_auth.py b/oauth_auth.py index c27bcea..374bec6 100644 --- a/oauth_auth.py +++ b/oauth_auth.py @@ -21,7 +21,8 @@ EMOJI = { 'SUCCESS': '✅', 'ERROR': '❌', 'WAIT': '⏳', - 'INFO': 'ℹ️' + 'INFO': 'ℹ️', + 'WARNING': '⚠️' } class OAuthHandler: @@ -85,6 +86,20 @@ class OAuthHandler: platform_name = platform.system().lower() print(f"{Fore.CYAN}{EMOJI['INFO']} Detected platform: {platform_name}{Style.RESET_ALL}") + # Linux-specific checks + if platform_name == 'linux': + # Check if DISPLAY is set + display = os.environ.get('DISPLAY') + if not display: + print(f"{Fore.RED}{EMOJI['ERROR']} No display found. Make sure X server is running.{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} Try: export DISPLAY=:0{Style.RESET_ALL}") + return False + + # Check if running as root + if os.geteuid() == 0: + print(f"{Fore.YELLOW}{EMOJI['WARNING']} Running as root is not recommended for browser automation{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} Consider running the script without sudo{Style.RESET_ALL}") + # Kill existing browser processes self._kill_browser_processes() @@ -103,7 +118,35 @@ class OAuthHandler: print(f"{Fore.CYAN}{EMOJI['INFO']} Using browser profile: {active_profile}{Style.RESET_ALL}") # Configure browser options - co = self._configure_browser_options(chrome_path, user_data_dir, active_profile) + co = ChromiumOptions() + + # Never use headless mode for OAuth flows + co.headless(False) + + # Platform-specific options + if platform_name == 'linux': + co.set_argument('--no-sandbox') + co.set_argument('--disable-dev-shm-usage') + co.set_argument('--disable-gpu') + + # If running as root, try to use actual user's Chrome profile + if os.geteuid() == 0: + sudo_user = os.environ.get('SUDO_USER') + if sudo_user: + actual_home = f"/home/{sudo_user}" + user_data_dir = os.path.join(actual_home, ".config", "google-chrome") + if os.path.exists(user_data_dir): + print(f"{Fore.CYAN}{EMOJI['INFO']} Using Chrome profile from: {user_data_dir}{Style.RESET_ALL}") + co.set_argument(f"--user-data-dir={user_data_dir}") + + # Set paths and profile + co.set_paths(browser_path=chrome_path, user_data_path=user_data_dir) + co.set_argument(f'--profile-directory={active_profile}') + + # Basic options + co.set_argument('--no-first-run') + co.set_argument('--no-default-browser-check') + co.auto_port() print(f"{Fore.CYAN}{EMOJI['INFO']} Starting browser at: {chrome_path}{Style.RESET_ALL}") self.browser = ChromiumPage(co) @@ -118,9 +161,11 @@ class OAuthHandler: except Exception as e: print(f"{Fore.RED}{EMOJI['ERROR']} Browser setup failed: {str(e)}{Style.RESET_ALL}") if "DevToolsActivePort file doesn't exist" in str(e): - print(f"{Fore.YELLOW}{EMOJI['INFO']} Try running with administrator/root privileges{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} Try running without sudo/administrator privileges{Style.RESET_ALL}") elif "Chrome failed to start" in str(e): print(f"{Fore.YELLOW}{EMOJI['INFO']} Make sure Chrome/Chromium is properly installed{Style.RESET_ALL}") + if platform_name == 'linux': + print(f"{Fore.YELLOW}{EMOJI['INFO']} Try: sudo apt install chromium-browser{Style.RESET_ALL}") return False def _kill_browser_processes(self): From 735dd8c1eb15c82790dc85e1615e790bc346981f Mon Sep 17 00:00:00 2001 From: yeongpin Date: Mon, 31 Mar 2025 11:58:54 +0800 Subject: [PATCH 3/3] refactor: enhance user feedback and error messages with translation support across multiple modules --- config.py | 66 +++++++------- locales/en.json | 77 +++++++++++++++-- locales/zh_cn.json | 70 ++++++++++++++- locales/zh_tw.json | 70 ++++++++++++++- new_tempemail.py | 10 +-- oauth_auth.py | 209 +++++++++++++++++++++++---------------------- 6 files changed, 347 insertions(+), 155 deletions(-) diff --git a/config.py b/config.py index 1d8e6bf..cf481c0 100644 --- a/config.py +++ b/config.py @@ -120,10 +120,10 @@ def setup_config(translator=None): break if not cursor_dir: - print(f"{Fore.YELLOW}{EMOJI['WARNING']} Neither Cursor nor cursor directory found in {config_base}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.neither_cursor_nor_cursor_directory_found', config_base=config_base) if translator else f'Neither Cursor nor cursor directory found in {config_base}'}{Style.RESET_ALL}") if root_home: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Also checked {root_home}/.config{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} Please make sure Cursor is installed and has been run at least once{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.also_checked', path=f'{root_home}/.config') if translator else f'Also checked {root_home}/.config'}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once') if translator else 'Please make sure Cursor is installed and has been run at least once'}{Style.RESET_ALL}") # Define Linux paths using the found cursor directory storage_path = os.path.abspath(os.path.join(cursor_dir, "User/globalStorage/storage.json")) if cursor_dir else "" @@ -133,50 +133,50 @@ def setup_config(translator=None): try: # Check storage directory if storage_dir and not os.path.exists(storage_dir): - print(f"{Fore.YELLOW}{EMOJI['WARNING']} Storage directory not found: {storage_dir}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} Please make sure Cursor is installed and has been run at least once{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_directory_not_found', storage_dir=storage_dir) if translator else f'Storage directory not found: {storage_dir}'}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once') if translator else 'Please make sure Cursor is installed and has been run at least once'}{Style.RESET_ALL}") # Check storage.json with more detailed verification if storage_path and os.path.exists(storage_path): # Get file stats try: stat = os.stat(storage_path) - print(f"{Fore.GREEN}{EMOJI['INFO']} Storage file found: {storage_path}{Style.RESET_ALL}") - print(f"{Fore.GREEN}{EMOJI['INFO']} File size: {stat.st_size} bytes{Style.RESET_ALL}") - print(f"{Fore.GREEN}{EMOJI['INFO']} File permissions: {oct(stat.st_mode & 0o777)}{Style.RESET_ALL}") - print(f"{Fore.GREEN}{EMOJI['INFO']} File owner: {stat.st_uid}{Style.RESET_ALL}") - print(f"{Fore.GREEN}{EMOJI['INFO']} File group: {stat.st_gid}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.storage_file_found', storage_path=storage_path) if translator else f'Storage file found: {storage_path}'}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_size', size=stat.st_size) if translator else f'File size: {stat.st_size} bytes'}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_permissions', permissions=oct(stat.st_mode & 0o777)) if translator else f'File permissions: {oct(stat.st_mode & 0o777)}'}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_owner', owner=stat.st_uid) if translator else f'File owner: {stat.st_uid}'}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_group', group=stat.st_gid) if translator else f'File group: {stat.st_gid}'}{Style.RESET_ALL}") except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Error getting file stats: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_getting_file_stats', error=str(e)) if translator else f'Error getting file stats: {str(e)}'}{Style.RESET_ALL}") # Check if file is readable and writable if not os.access(storage_path, os.R_OK | os.W_OK): - print(f"{Fore.RED}{EMOJI['ERROR']} Permission denied: {storage_path}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.permission_denied', storage_path=storage_path) if translator else f'Permission denied: {storage_path}'}{Style.RESET_ALL}") if sudo_user: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Try running: chown {sudo_user}:{sudo_user} {storage_path}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} And: chmod 644 {storage_path}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.try_running', command=f'chown {sudo_user}:{sudo_user} {storage_path}') if translator else f'Try running: chown {sudo_user}:{sudo_user} {storage_path}'}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.and') if translator else 'And'}: chmod 644 {storage_path}{Style.RESET_ALL}") else: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Try running: chown {current_user}:{current_user} {storage_path}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} And: chmod 644 {storage_path}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.try_running', command=f'chown {current_user}:{current_user} {storage_path}') if translator else f'Try running: chown {current_user}:{current_user} {storage_path}'}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.and') if translator else 'And'}: chmod 644 {storage_path}{Style.RESET_ALL}") # Try to read the file to verify it's not corrupted try: with open(storage_path, 'r') as f: content = f.read() if not content.strip(): - print(f"{Fore.YELLOW}{EMOJI['WARNING']} Storage file is empty: {storage_path}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} Please make sure Cursor is installed and has been run at least once{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_file_is_empty', storage_path=storage_path) if translator else f'Storage file is empty: {storage_path}'}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.the_file_might_be_corrupted_please_reinstall_cursor') if translator else 'The file might be corrupted, please reinstall Cursor'}{Style.RESET_ALL}") else: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Storage file is valid and contains data{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('config.storage_file_is_valid_and_contains_data') if translator else 'Storage file is valid and contains data'}{Style.RESET_ALL}") except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Error reading storage file: {str(e)}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} The file might be corrupted. Please reinstall Cursor{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_reading_storage_file', error=str(e)) if translator else f'Error reading storage file: {str(e)}'}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.the_file_might_be_corrupted_please_reinstall_cursor') if translator else 'The file might be corrupted. Please reinstall Cursor'}{Style.RESET_ALL}") elif storage_path: - print(f"{Fore.YELLOW}{EMOJI['WARNING']} Storage file not found: {storage_path}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} Please make sure Cursor is installed and has been run at least once{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_file_not_found', storage_path=storage_path) if translator else f'Storage file not found: {storage_path}'}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once') if translator else 'Please make sure Cursor is installed and has been run at least once'}{Style.RESET_ALL}") except (OSError, IOError) as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Error checking Linux paths: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_checking_linux_paths', error=str(e)) if translator else f'Error checking Linux paths: {str(e)}'}{Style.RESET_ALL}") # Define all paths using the found cursor directory default_config['LinuxPaths'] = { @@ -202,13 +202,13 @@ def setup_config(translator=None): config.set(section, option, str(value)) config_modified = True if translator: - print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('register.config_option_added', option=f'{section}.{option}')}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.config_option_added', option=f'{section}.{option}') if translator else f'Config option added: {section}.{option}'}{Style.RESET_ALL}") if config_modified: with open(config_file, 'w', encoding='utf-8') as f: config.write(f) if translator: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('register.config_updated')}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('config.config_updated') if translator else 'Config updated'}{Style.RESET_ALL}") else: for section, options in default_config.items(): config.add_section(section) @@ -218,31 +218,31 @@ def setup_config(translator=None): with open(config_file, 'w', encoding='utf-8') as f: config.write(f) if translator: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('register.config_created')}: {config_file}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('config.config_created', config_file=config_file) if translator else f'Config created: {config_file}'}{Style.RESET_ALL}") return config except Exception as e: if translator: - print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('register.config_setup_error', error=str(e))}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.config_setup_error', error=str(e)) if translator else f'Error setting up config: {str(e)}'}{Style.RESET_ALL}") return None def print_config(config, translator=None): """Print configuration in a readable format""" if not config: - print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.config_not_available')}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.config_not_available') if translator else 'Configuration not available'}{Style.RESET_ALL}") return - print(f"\n{Fore.CYAN}{EMOJI['INFO']} {translator.get('config.configuration')}:{Style.RESET_ALL}") + print(f"\n{Fore.CYAN}{EMOJI['INFO']} {translator.get('config.configuration') if translator else 'Configuration'}:{Style.RESET_ALL}") print(f"\n{Fore.CYAN}{'─' * 70}{Style.RESET_ALL}") for section in config.sections(): print(f"{Fore.GREEN}[{section}]{Style.RESET_ALL}") for key, value in config.items(section): # 对布尔值进行特殊处理,使其显示为彩色 if value.lower() in ('true', 'yes', 'on', '1'): - value_display = f"{Fore.GREEN}{translator.get('config.enabled')}{Style.RESET_ALL}" + value_display = f"{Fore.GREEN}{translator.get('config.enabled') if translator else 'Enabled'}{Style.RESET_ALL}" elif value.lower() in ('false', 'no', 'off', '0'): - value_display = f"{Fore.RED}{translator.get('config.disabled')}{Style.RESET_ALL}" + value_display = f"{Fore.RED}{translator.get('config.disabled') if translator else 'Disabled'}{Style.RESET_ALL}" else: value_display = value @@ -250,7 +250,7 @@ def print_config(config, translator=None): print(f"\n{Fore.CYAN}{'─' * 70}{Style.RESET_ALL}") config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip", "config.ini") - print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('config.config_directory')}: {config_dir}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('config.config_directory') if translator else 'Config Directory'}: {config_dir}{Style.RESET_ALL}") print() diff --git a/locales/en.json b/locales/en.json index c3bef05..05a4877 100644 --- a/locales/en.json +++ b/locales/en.json @@ -280,7 +280,13 @@ "available_domains_loaded": "Available Domains Loaded: {count}", "domains_filtered": "Domains Filtered: {count}", "trying_to_create_email": "Trying to create email: {email}", - "domain_blocked": "Domain Blocked: {domain}" + "domain_blocked": "Domain Blocked: {domain}", + "using_chrome_profile": "Using Chrome profile from: {user_data_dir}", + "no_display_found": "No display found. Make sure X server is running.", + "try_export_display": "Try: export DISPLAY=:0", + "extension_load_error": "Extension Load Error: {error}", + "make_sure_chrome_chromium_is_properly_installed": "Make sure Chrome/Chromium is properly installed", + "try_install_chromium": "Try: sudo apt install chromium-browser" }, "update": { "title": "Disable Cursor Auto Update", @@ -498,14 +504,14 @@ "please_make_sure_cursor_is_installed_and_has_been_run_at_least_once": "Please make sure Cursor is installed and has been run at least once", "storage_directory_not_found": "Storage directory not found: {storage_dir}", "storage_file_found": "Storage file found: {storage_path}", - "file_size": "File size: {size}", + "file_size": "File size: {size} bytes", "file_permissions": "File permissions: {permissions}", "file_owner": "File owner: {owner}", "file_group": "File group: {group}", "error_getting_file_stats": "Error getting file stats: {error}", "permission_denied": "Permission denied: {storage_path}", - "try_running": "Try running 'cursor --help' to check if it's installed", - "and": "and", + "try_running": "Try running: {command}", + "and": "And", "storage_file_is_empty": "Storage file is empty: {storage_path}", "the_file_might_be_corrupted_please_reinstall_cursor": "The file might be corrupted, please reinstall Cursor", "storage_file_not_found": "Storage file not found: {storage_path}", @@ -513,7 +519,64 @@ "config_option_added": "Config option added: {option}", "config_updated": "Config updated", "config_created": "Config created: {config_file}", - "config_setup_error": "Error setting up config: {error}" - + "config_setup_error": "Error setting up config: {error}", + "storage_file_is_valid_and_contains_data": "Storage file is valid and contains data", + "error_reading_storage_file": "Error reading storage file: {error}", + "also_checked": "Also checked {path}" + }, + "oauth": { + "authentication_button_not_found": "Authentication button not found", + "authentication_failed": "Authentication failed: {error}", + "found_cookies": "Found {count} cookies", + "token_extraction_error": "Token extraction error: {error}", + "authentication_successful": "Authentication successful - Email: {email}", + "missing_authentication_data": "Missing authentication data: {data}", + "failed_to_delete_account": "Failed to delete account: {error}", + "invalid_authentication_type": "Invalid authentication type", + "auth_update_success": "Auth update success", + "browser_closed": "Browser closed", + "auth_update_failed": "Auth update failed", + "google_start": "Google start", + "github_start": "Github start", + "usage_count": "Usage count: {usage}", + "account_has_reached_maximum_usage": "Account has reached maximum usage, {deleting}", + "starting_new_authentication_process": "Starting new authentication process...", + "failed_to_delete_expired_account": "Failed to delete expired account", + "could_not_check_usage_count": "Could not check usage count: {error}", + "found_email": "Found email: {email}", + "could_not_find_email": "Could not find email: {error}", + "could_not_find_usage_count": "Could not find usage count: {error}", + "already_on_settings_page": "Already on settings page!", + "failed_to_extract_auth_info": "Failed to extract auth info: {error}", + "no_chrome_profiles_found": "No Chrome profiles found, using Default", + "found_default_chrome_profile": "Found Default Chrome profile", + "using_first_available_chrome_profile": "Using first available Chrome profile: {profile}", + "error_finding_chrome_profile": "Error finding Chrome profile, using Default: {error}", + "initializing_browser_setup": "Initializing browser setup...", + "detected_platform": "Detected platform: {platform}", + "running_as_root_warning": "Running as root is not recommended for browser automation", + "consider_running_without_sudo": "Consider running the script without sudo", + "no_compatible_browser_found": "No compatible browser found. Please install Google Chrome or Chromium.", + "supported_browsers": "Supported browsers for {platform}", + "using_browser_profile": "Using browser profile: {profile}", + "starting_browser": "Starting browser at: {path}", + "browser_setup_completed": "Browser setup completed successfully", + "browser_setup_failed": "Browser setup failed: {error}", + "try_running_without_sudo_admin": "Try running without sudo/administrator privileges", + "redirecting_to_authenticator_cursor_sh": "Redirecting to authenticator.cursor.sh...", + "starting_google_authentication": "Starting Google authentication...", + "starting_github_authentication": "Starting GitHub authentication...", + "waiting_for_authentication": "Waiting for authentication...", + "page_changed_checking_auth": "Page changed, checking auth...", + "status_check_error": "Status check error: {error}", + "authentication_timeout": "Authentication timeout", + "account_is_still_valid": "Account is still valid (Usage: {usage})", + "starting_re_authentication_process": "Starting re-authentication process...", + "starting_new_google_authentication": "Starting new Google authentication...", + "failed_to_delete_account_or_re_authenticate": "Failed to delete account or re-authenticate: {error}", + "navigating_to_authentication_page": "Navigating to authentication page...", + "please_select_your_google_account_to_continue": "Please select your Google account to continue...", + "found_browser_data_directory": "Found browser data directory: {path}", + "authentication_successful_getting_account_info": "Authentication successful, getting account info..." } -} \ No newline at end of file +} \ No newline at end of file diff --git a/locales/zh_cn.json b/locales/zh_cn.json index 05710fe..4bf37ed 100644 --- a/locales/zh_cn.json +++ b/locales/zh_cn.json @@ -275,7 +275,13 @@ "available_domains_loaded": "获取到 {count} 个可用域名", "domains_filtered": "过滤后剩餘 {count} 個可用域名", "trying_to_create_email": "尝试创建邮箱: {email}", - "domain_blocked": "域名被屏蔽: {domain}" + "domain_blocked": "域名被屏蔽: {domain}", + "using_chrome_profile": "使用 Chrome 配置文件: {user_data_dir}", + "no_display_found": "未找到显示器。确保 X 服务器正在运行。", + "try_export_display": "尝试: export DISPLAY=:0", + "extension_load_error": "加载插件失败: {error}", + "make_sure_chrome_chromium_is_properly_installed": "确保 Chrome/Chromium 已正确安装", + "try_install_chromium": "尝试: sudo apt install chromium-browser" }, "update": { "title": "禁用 Cursor 自动更新", @@ -499,7 +505,7 @@ "file_group": "文件组", "error_getting_file_stats": "获取文件统计信息时出错", "permission_denied": "权限拒绝", - "try_running": "尝试运行 'cursor --help' 检查是否已安装", + "try_running": "尝试运行: {command}", "and": "和", "storage_file_is_empty": "存储文件为空", "the_file_might_be_corrupted_please_reinstall_cursor": "文件可能已损坏,请重新安装 Cursor", @@ -508,7 +514,65 @@ "config_option_added": "添加配置选项", "config_updated": "配置更新", "config_created": "配置已创建", - "config_setup_error": "配置设置错误" + "config_setup_error": "配置设置错误", + "storage_file_is_valid_and_contains_data": "存储文件有效且包含数据", + "error_reading_storage_file": "读取存储文件时出错", + "also_checked": "也检查了 {path}" + }, + "oauth": { + "authentication_button_not_found": "未找到认证按钮", + "authentication_failed": "认证失败: {error}", + "found_cookies": "找到 {count} 个 Cookie", + "token_extraction_error": "Token 提取错误: {error}", + "authentication_successful": "认证成功 - 邮箱: {email}", + "missing_authentication_data": "缺少认证数据: {data}", + "failed_to_delete_account": "删除账户失败: {error}", + "invalid_authentication_type": "无效的认证类型", + "auth_update_success": "认证更新成功", + "browser_closed": "浏览器已关闭", + "auth_update_failed": "认证更新失败", + "google_start": "Google 开始", + "github_start": "Github 开始", + "usage_count": "使用次数: {usage}", + "account_has_reached_maximum_usage": "账户已达到最大使用量, {deleting}", + "starting_new_authentication_process": "开始新的认证过程...", + "failed_to_delete_expired_account": "删除过期账户失败", + "could_not_check_usage_count": "无法检查使用次数: {error}", + "found_email": "找到邮箱: {email}", + "could_not_find_email": "未找到邮箱: {error}", + "could_not_find_usage_count": "未找到使用次数: {error}", + "already_on_settings_page": "已处于设置页面", + "failed_to_extract_auth_info": "提取认证信息失败: {error}", + "no_chrome_profiles_found": "未找到 Chrome 配置文件, 使用默认配置文件", + "found_default_chrome_profile": "找到默认 Chrome 配置文件", + "using_first_available_chrome_profile": "使用第一个可用的 Chrome 配置文件: {profile}", + "error_finding_chrome_profile": "找不到 Chrome 配置文件, 使用默认配置文件: {error}", + "initializing_browser_setup": "初始化浏览器设置...", + "detected_platform": "检测平台: {platform}", + "running_as_root_warning": "以 root 运行不推荐用于浏览器自动化", + "consider_running_without_sudo": "考虑不使用 sudo 运行脚本", + "no_compatible_browser_found": "未找到兼容的浏览器。请安装 Google Chrome 或 Chromium。", + "supported_browsers": "支持的浏览器: {platform}", + "using_browser_profile": "使用浏览器配置文件: {profile}", + "starting_browser": "正在启动浏览器: {path}", + "browser_setup_completed": "浏览器设置完成", + "browser_setup_failed": "浏览器设置失败: {error}", + "try_running_without_sudo_admin": "尝试不使用 sudo/管理员权限运行", + "redirecting_to_authenticator_cursor_sh": "重定向到 authenticator.cursor.sh...", + "starting_google_authentication": "开始 Google 认证...", + "starting_github_authentication": "开始 Github 认证...", + "waiting_for_authentication": "等待认证...", + "page_changed_checking_auth": "页面改变, 检查认证...", + "status_check_error": "状态检查错误: {error}", + "authentication_timeout": "认证超时", + "account_is_still_valid": "账户仍然有效 (使用量: {usage})", + "starting_re_authentication_process": "开始重新认证过程...", + "starting_new_google_authentication": "开始新的 Google 认证...", + "failed_to_delete_account_or_re_authenticate": "删除账户或重新认证失败: {error}", + "navigating_to_authentication_page": "正在导航到认证页面...", + "please_select_your_google_account_to_continue": "请选择您的 Google 账户以继续...", + "found_browser_data_directory": "找到浏览器数据目录: {path}", + "authentication_successful_getting_account_info": "认证成功, 获取账户信息..." } } \ No newline at end of file diff --git a/locales/zh_tw.json b/locales/zh_tw.json index c88ae6e..bca1a83 100644 --- a/locales/zh_tw.json +++ b/locales/zh_tw.json @@ -254,7 +254,14 @@ "blocked_domains_loaded_timeout_error": "加載被屏蔽的域名超時錯誤: {error}", "available_domains_loaded": "獲取到 {count} 個可用域名", "domains_filtered": "過濾後剩餘 {count} 個可用域名", - "trying_to_create_email": "嘗試創建郵箱: {email}" + "trying_to_create_email": "嘗試創建郵箱: {email}", + "domain_blocked": "域名被屏蔽: {domain}", + "using_chrome_profile": "使用 Chrome 配置文件: {user_data_dir}", + "no_display_found": "未找到顯示器。確保 X 伺服器正在運行。", + "try_export_display": "嘗試: export DISPLAY=:0", + "extension_load_error": "加載插件失敗: {error}", + "make_sure_chrome_chromium_is_properly_installed": "確保 Chrome/Chromium 已正確安裝", + "try_install_chromium": "嘗試: sudo apt install chromium-browser" }, "update": { "title": "禁用 Cursor 自动更新", @@ -478,7 +485,7 @@ "file_group": "文件組", "error_getting_file_stats": "獲取文件統計信息時出錯", "permission_denied": "權限拒絕", - "try_running": "嘗試運行 'cursor --help' 檢查是否已安裝", + "try_running": "嘗試運行: {command}", "and": "和", "storage_file_is_empty": "儲存文件為空", "the_file_might_be_corrupted_please_reinstall_cursor": "文件可能已損壞,請重新安裝 Cursor", @@ -487,7 +494,64 @@ "config_option_added": "添加配置選項", "config_updated": "配置更新", "config_created": "配置已創建", - "config_setup_error": "配置設置錯誤" + "config_setup_error": "配置設置錯誤", + "storage_file_is_valid_and_contains_data": "儲存文件有效且包含數據", + "error_reading_storage_file": "讀取儲存文件時出錯", + "also_checked": "也檢查了 {path}" + }, + "oauth": { + "authentication_button_not_found": "未找到認證按鈕", + "authentication_failed": "認證失敗: {error}", + "found_cookies": "找到 {count} 個 Cookie", + "token_extraction_error": "Token 提取錯誤: {error}", + "authentication_successful": "認證成功 - 郵箱: {email}", + "missing_authentication_data": "缺少認證數據: {data}", + "failed_to_delete_account": "刪除帳戶失敗: {error}", + "invalid_authentication_type": "無效的認證類型", + "auth_update_success": "認證更新成功", + "browser_closed": "瀏覽器已關閉", + "auth_update_failed": "認證更新失敗", + "google_start": "Google 開始", + "github_start": "Github 開始", + "usage_count": "使用量: {usage}", + "account_has_reached_maximum_usage": "帳戶已達到最大使用量, {deleting}", + "starting_new_authentication_process": "開始新的認證過程...", + "failed_to_delete_expired_account": "刪除過期帳戶失敗", + "could_not_check_usage_count": "無法檢查使用量: {error}", + "found_email": "找到郵箱: {email}", + "could_not_find_email": "未找到郵箱: {error}", + "could_not_find_usage_count": "未找到使用量: {erro r}", + "already_on_settings_page": "已處於設置頁面", + "failed_to_extract_auth_info": "提取認證信息失敗: {error}", + "no_chrome_profiles_found": "未找到 Chrome 配置文件, 使用默認配置文件", + "found_default_chrome_profile": "找到默認 Chrome 配置文件", + "using_first_available_chrome_profile": "使用第一個可用的 Chrome 配置文件: {profile}", + "error_finding_chrome_profile": "找不到 Chrome 配置文件, 使用默認配置文件: {error}", + "initializing_browser_setup": "初始化瀏覽器設置...", + "detected_platform": "檢測平台: {platform}", + "running_as_root_warning": "以 root 運行不推薦用於瀏覽器自動化", + "consider_running_without_sudo": "考慮不使用 sudo 運行腳本", + "no_compatible_browser_found": "未找到兼容的瀏覽器。請安裝 Google Chrome 或 Chromium。", + "supported_browsers": "支持的瀏覽器: {platform}", + "using_browser_profile": "使用瀏覽器配置文件: {profile}", + "starting_browser": "正在啟動瀏覽器: {path}", + "browser_setup_completed": "瀏覽器設置完成成功", + "browser_setup_failed": "瀏覽器設置失敗: {error}", + "try_running_without_sudo_admin": "嘗試不使用 sudo/管理員權限運行", + "redirecting_to_authenticator_cursor_sh": "重定向到 authenticator.cursor.sh...", + "starting_github_authentication": "開始 Github 認證...", + "waiting_for_authentication": "等待認證...", + "page_changed_checking_auth": "頁面改變, 檢查認證...", + "status_check_error": "狀態檢查錯誤: {error}", + "authentication_timeout": "認證超時", + "account_is_still_valid": "帳戶仍然有效 (使用量: {usage})", + "starting_re_authentication_process": "開始重新認證過程...", + "starting_new_google_authentication": "開始新的 Google 認證...", + "failed_to_delete_account_or_re_authenticate": "刪除帳戶或重新認證失敗: {error}", + "navigating_to_authentication_page": "正在導航到認證頁面...", + "please_select_your_google_account_to_continue": "請選擇您的 Google 帳戶以繼續...", + "found_browser_data_directory": "找到瀏覽器數據目錄: {path}", + "authentication_successful_getting_account_info": "認證成功, 獲取帳戶信息..." } } \ No newline at end of file diff --git a/new_tempemail.py b/new_tempemail.py index dfb96b3..178f24f 100644 --- a/new_tempemail.py +++ b/new_tempemail.py @@ -114,8 +114,8 @@ class NewTempEmail: if sys.platform == "linux": # Check if DISPLAY is set when not in headless mode if not co.arguments.get("--headless=new") and not os.environ.get('DISPLAY'): - print(f"{Fore.RED}❌ No display found. Make sure X server is running.{Style.RESET_ALL}") - print(f"{Fore.YELLOW}ℹ️ Try: export DISPLAY=:0{Style.RESET_ALL}") + print(f"{Fore.RED}❌ {self.translator.get('email.no_display_found') if self.translator else 'No display found. Make sure X server is running.'}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}ℹ️ {self.translator.get('email.try_export_display') if self.translator else 'Try: export DISPLAY=:0'}{Style.RESET_ALL}") return False co.set_argument("--no-sandbox") @@ -129,7 +129,7 @@ class NewTempEmail: actual_home = f"/home/{sudo_user}" user_data_dir = os.path.join(actual_home, ".config", "google-chrome") if os.path.exists(user_data_dir): - print(f"{Fore.CYAN}ℹ️ Using Chrome profile from: {user_data_dir}{Style.RESET_ALL}") + print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.using_chrome_profile', user_data_dir=user_data_dir) if self.translator else f'Using Chrome profile from: {user_data_dir}'}{Style.RESET_ALL}") co.set_argument(f"--user-data-dir={user_data_dir}") co.auto_port() # 自动设置端口 @@ -154,8 +154,8 @@ class NewTempEmail: print(f"{Fore.RED}❌ 启动浏览器失败: {str(e)}{Style.RESET_ALL}") if sys.platform == "linux": - print(f"{Fore.YELLOW}ℹ️ Make sure Chrome/Chromium is properly installed{Style.RESET_ALL}") - print(f"{Fore.YELLOW}ℹ️ Try: sudo apt install chromium-browser{Style.RESET_ALL}") + print(f"{Fore.YELLOW}ℹ️ {self.translator.get('email.make_sure_chrome_chromium_is_properly_installed') if self.translator else 'Make sure Chrome/Chromium is properly installed'}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}ℹ️ {self.translator.get('email.try_install_chromium') if self.translator else 'Try: sudo apt install chromium-browser'}{Style.RESET_ALL}") return False def create_email(self): diff --git a/oauth_auth.py b/oauth_auth.py index 374bec6..6dc4c71 100644 --- a/oauth_auth.py +++ b/oauth_auth.py @@ -43,12 +43,12 @@ class OAuthHandler: profiles.append(item) if not profiles: - print(f"{Fore.YELLOW}{EMOJI['INFO']} No Chrome profiles found, using Default{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.no_chrome_profiles_found') if self.translator else 'No Chrome profiles found, using Default'}{Style.RESET_ALL}") return 'Default' # First check if Default profile exists if 'Default' in profiles: - print(f"{Fore.CYAN}{EMOJI['INFO']} Found Default Chrome profile{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_default_chrome_profile') if self.translator else 'Found Default Chrome profile'}{Style.RESET_ALL}") return 'Default' # If no Default profile, check Local State for last used profile @@ -70,35 +70,35 @@ class OAuthHandler: return profile # If no profile found in Local State, use the first available profile - print(f"{Fore.CYAN}{EMOJI['INFO']} Using first available Chrome profile: {profiles[0]}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.using_first_available_chrome_profile', profile=profiles[0]) if self.translator else f'Using first available Chrome profile: {profiles[0]}'}{Style.RESET_ALL}") return profiles[0] except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Error finding Chrome profile, using Default: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.error_finding_chrome_profile', error=str(e)) if self.translator else f'Error finding Chrome profile, using Default: {str(e)}'}{Style.RESET_ALL}") return 'Default' def setup_browser(self): """Setup browser for OAuth flow using active profile""" try: - print(f"{Fore.CYAN}{EMOJI['INFO']} Initializing browser setup...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.initializing_browser_setup') if self.translator else 'Initializing browser setup...'}{Style.RESET_ALL}") # Platform-specific initialization platform_name = platform.system().lower() - print(f"{Fore.CYAN}{EMOJI['INFO']} Detected platform: {platform_name}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.detected_platform', platform=platform_name) if self.translator else f'Detected platform: {platform_name}'}{Style.RESET_ALL}") # Linux-specific checks if platform_name == 'linux': # Check if DISPLAY is set display = os.environ.get('DISPLAY') if not display: - print(f"{Fore.RED}{EMOJI['ERROR']} No display found. Make sure X server is running.{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} Try: export DISPLAY=:0{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.no_display_found') if self.translator else 'No display found. Make sure X server is running.'}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.try_export_display') if self.translator else 'Try: export DISPLAY=:0'}{Style.RESET_ALL}") return False # Check if running as root if os.geteuid() == 0: - print(f"{Fore.YELLOW}{EMOJI['WARNING']} Running as root is not recommended for browser automation{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} Consider running the script without sudo{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('oauth.running_as_root_warning') if self.translator else 'Running as root is not recommended for browser automation'}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.consider_running_without_sudo') if self.translator else 'Consider running the script without sudo'}{Style.RESET_ALL}") # Kill existing browser processes self._kill_browser_processes() @@ -108,14 +108,14 @@ class OAuthHandler: chrome_path = self._get_browser_path() if not chrome_path: - raise Exception(f"No compatible browser found. Please install Google Chrome or Chromium.\nSupported browsers for {platform_name}:\n" + + raise Exception(f"{self.translator.get('oauth.no_compatible_browser_found') if self.translator else 'No compatible browser found. Please install Google Chrome or Chromium.'}\n{self.translator.get('oauth.supported_browsers', platform=platform_name)}\n" + "- Windows: Google Chrome, Chromium\n" + "- macOS: Google Chrome, Chromium\n" + "- Linux: Google Chrome, Chromium, chromium-browser") # Get active profile active_profile = self._get_active_profile(user_data_dir) - print(f"{Fore.CYAN}{EMOJI['INFO']} Using browser profile: {active_profile}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.using_browser_profile', profile=active_profile) if self.translator else f'Using browser profile: {active_profile}'}{Style.RESET_ALL}") # Configure browser options co = ChromiumOptions() @@ -124,7 +124,7 @@ class OAuthHandler: co.headless(False) # Platform-specific options - if platform_name == 'linux': + if os.name == 'linux': co.set_argument('--no-sandbox') co.set_argument('--disable-dev-shm-usage') co.set_argument('--disable-gpu') @@ -136,7 +136,7 @@ class OAuthHandler: actual_home = f"/home/{sudo_user}" user_data_dir = os.path.join(actual_home, ".config", "google-chrome") if os.path.exists(user_data_dir): - print(f"{Fore.CYAN}{EMOJI['INFO']} Using Chrome profile from: {user_data_dir}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.using_chrome_profile_from', user_data_dir=user_data_dir) if self.translator else f'Using Chrome profile from: {user_data_dir}'}{Style.RESET_ALL}") co.set_argument(f"--user-data-dir={user_data_dir}") # Set paths and profile @@ -146,26 +146,26 @@ class OAuthHandler: # Basic options co.set_argument('--no-first-run') co.set_argument('--no-default-browser-check') - co.auto_port() + # co.auto_port() - print(f"{Fore.CYAN}{EMOJI['INFO']} Starting browser at: {chrome_path}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_browser', path=chrome_path) if self.translator else f'Starting browser at: {chrome_path}'}{Style.RESET_ALL}") self.browser = ChromiumPage(co) # Verify browser launched successfully if not self.browser: raise Exception("Failed to initialize browser instance") - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Browser setup completed successfully{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.browser_setup_completed') if self.translator else 'Browser setup completed successfully'}{Style.RESET_ALL}") return True except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Browser setup failed: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.browser_setup_failed', error=str(e)) if self.translator else f'Browser setup failed: {str(e)}'}{Style.RESET_ALL}") if "DevToolsActivePort file doesn't exist" in str(e): - print(f"{Fore.YELLOW}{EMOJI['INFO']} Try running without sudo/administrator privileges{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.try_running_without_sudo_admin') if self.translator else 'Try running without sudo/administrator privileges'}{Style.RESET_ALL}") elif "Chrome failed to start" in str(e): - print(f"{Fore.YELLOW}{EMOJI['INFO']} Make sure Chrome/Chromium is properly installed{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.make_sure_chrome_chromium_is_properly_installed') if self.translator else 'Make sure Chrome/Chromium is properly installed'}{Style.RESET_ALL}") if platform_name == 'linux': - print(f"{Fore.YELLOW}{EMOJI['INFO']} Try: sudo apt install chromium-browser{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.try_install_chromium') if self.translator else 'Try: sudo apt install chromium-browser'}{Style.RESET_ALL}") return False def _kill_browser_processes(self): @@ -182,7 +182,7 @@ class OAuthHandler: time.sleep(1) # Wait for processes to close except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Warning: Could not kill existing browser processes: {e}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.warning_could_not_kill_existing_browser_processes', error=str(e)) if self.translator else f'Warning: Could not kill existing browser processes: {e}'}{Style.RESET_ALL}") def _get_user_data_directory(self): """Get the appropriate user data directory based on platform""" @@ -208,17 +208,17 @@ class OAuthHandler: # Try each possible path for path in possible_paths: if os.path.exists(path): - print(f"{Fore.CYAN}{EMOJI['INFO']} Found browser data directory: {path}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_browser_data_directory', path=path) if self.translator else f'Found browser data directory: {path}'}{Style.RESET_ALL}") return path # Create temporary profile if no existing profile found temp_profile = os.path.join(os.path.expanduser('~'), '.cursor_temp_profile') - print(f"{Fore.YELLOW}{EMOJI['INFO']} Creating temporary profile at: {temp_profile}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.creating_temporary_profile', path=temp_profile) if self.translator else f'Creating temporary profile at: {temp_profile}'}{Style.RESET_ALL}") os.makedirs(temp_profile, exist_ok=True) return temp_profile except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Error getting user data directory: {e}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_getting_user_data_directory', error=str(e)) if self.translator else f'Error getting user data directory: {e}'}{Style.RESET_ALL}") raise def _get_browser_path(self): @@ -229,7 +229,7 @@ class OAuthHandler: if chrome_path and os.path.exists(chrome_path): return chrome_path - print(f"{Fore.YELLOW}{EMOJI['INFO']} Searching for alternative browser installations...{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.searching_for_alternative_browser_installations') if self.translator else 'Searching for alternative browser installations...'}{Style.RESET_ALL}") # Platform-specific paths if os.name == 'nt': # Windows @@ -261,13 +261,13 @@ class OAuthHandler: for path in alt_paths: expanded_path = os.path.expanduser(path) if os.path.exists(expanded_path): - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Found browser at: {expanded_path}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.found_browser_at', path=expanded_path) if self.translator else f'Found browser at: {expanded_path}'}{Style.RESET_ALL}") return expanded_path return None except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Error finding browser path: {e}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_finding_browser_path', error=str(e)) if self.translator else f'Error finding browser path: {e}'}{Style.RESET_ALL}") return None def _configure_browser_options(self, chrome_path, user_data_dir, active_profile): @@ -296,22 +296,22 @@ class OAuthHandler: return co except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Error configuring browser options: {e}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_configuring_browser_options', error=str(e)) if self.translator else f'Error configuring browser options: {e}'}{Style.RESET_ALL}") raise def handle_google_auth(self): """Handle Google OAuth authentication""" try: - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.google_start')}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.google_start') if self.translator else 'Starting Google OAuth authentication...'}{Style.RESET_ALL}") # Setup browser if not self.setup_browser(): - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.browser_failed')}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.browser_failed') if self.translator else 'Browser failed to initialize'}{Style.RESET_ALL}") return False, None # Navigate to auth URL try: - print(f"{Fore.CYAN}{EMOJI['INFO']} Navigating to authentication page...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.navigating_to_authentication_page') if self.translator else 'Navigating to authentication page...'}{Style.RESET_ALL}") self.browser.get("https://authenticator.cursor.sh/sign-up") time.sleep(get_random_wait_time(self.config, 'page_load_wait')) @@ -335,16 +335,17 @@ class OAuthHandler: raise Exception("Could not find Google authentication button") # Click the button and wait for page load - print(f"{Fore.CYAN}{EMOJI['INFO']} Starting Google authentication...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_google_authentication') if self.translator else 'Starting Google authentication...'}{Style.RESET_ALL}") auth_btn.click() time.sleep(get_random_wait_time(self.config, 'page_load_wait')) # Check if we're on account selection page if "accounts.google.com" in self.browser.url: - print(f"{Fore.CYAN}{EMOJI['INFO']} Please select your Google account to continue...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.please_select_your_google_account_to_continue') if self.translator else 'Please select your Google account to continue...'}{Style.RESET_ALL}") + alert_message = self.translator.get('oauth.please_select_your_google_account_to_continue') if self.translator else 'Please select your Google account to continue with Cursor authentication' try: - self.browser.run_js(""" - alert('Please select your Google account to continue with Cursor authentication'); + self.browser.run_js(f""" + alert('{alert_message}'); """) except: pass # Alert is optional @@ -352,14 +353,14 @@ class OAuthHandler: # Wait for authentication to complete auth_info = self._wait_for_auth() if not auth_info: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.timeout')}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.timeout') if self.translator else 'Timeout'}{Style.RESET_ALL}") return False, None - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.success')}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.success') if self.translator else 'Success'}{Style.RESET_ALL}") return True, auth_info except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Authentication error: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_error', error=str(e)) if self.translator else f'Authentication error: {str(e)}'}{Style.RESET_ALL}") return False, None finally: try: @@ -379,7 +380,7 @@ class OAuthHandler: start_time = time.time() check_interval = 2 # Check every 2 seconds - print(f"{Fore.CYAN}{EMOJI['WAIT']} Waiting for authentication (timeout: 5 minutes)...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('oauth.waiting_for_authentication', timeout='5 minutes') if self.translator else 'Waiting for authentication (timeout: 5 minutes)'}{Style.RESET_ALL}") while time.time() - start_time < max_wait: try: @@ -398,7 +399,7 @@ class OAuthHandler: if token: # Get email from settings page - print(f"{Fore.CYAN}{EMOJI['INFO']} Authentication successful, getting account info...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.authentication_successful_getting_account_info') if self.translator else 'Authentication successful, getting account info...'}{Style.RESET_ALL}") self.browser.get("https://www.cursor.com/settings") time.sleep(3) @@ -407,7 +408,7 @@ class OAuthHandler: email_element = self.browser.ele("css:div[class='flex w-full flex-col gap-2'] div:nth-child(2) p:nth-child(2)") if email_element: email = email_element.text - print(f"{Fore.CYAN}{EMOJI['INFO']} Found email: {email}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_email', email=email) if self.translator else f'Found email: {email}'}{Style.RESET_ALL}") except: email = "user@cursor.sh" # Fallback email @@ -416,42 +417,42 @@ class OAuthHandler: usage_element = self.browser.ele("css:div[class='flex flex-col gap-4 lg:flex-row'] div:nth-child(1) div:nth-child(1) span:nth-child(2)") if usage_element: usage_text = usage_element.text - print(f"{Fore.CYAN}{EMOJI['INFO']} Usage count: {usage_text}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.usage_count', usage=usage_text) if self.translator else f'Usage count: {usage_text}'}{Style.RESET_ALL}") # Check if account is expired if usage_text.strip() == "150 / 150": - print(f"{Fore.YELLOW}{EMOJI['INFO']} Account has reached maximum usage, creating new account...{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.account_has_reached_maximum_usage', creating_new_account='creating new account') if self.translator else 'Account has reached maximum usage, creating new account...'}{Style.RESET_ALL}") # Delete current account if self._delete_current_account(): # Start new authentication based on auth type - print(f"{Fore.CYAN}{EMOJI['INFO']} Starting new authentication process...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_new_authentication_process') if self.translator else 'Starting new authentication process...'}{Style.RESET_ALL}") if self.auth_type == "google": return self.handle_google_auth() else: # github return self.handle_github_auth() else: - print(f"{Fore.RED}{EMOJI['ERROR']} Failed to delete expired account{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_delete_expired_account') if self.translator else 'Failed to delete expired account'}{Style.RESET_ALL}") except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Could not check usage count: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_check_usage_count', error=str(e)) if self.translator else f'Could not check usage count: {str(e)}'}{Style.RESET_ALL}") return {"email": email, "token": token} # Also check URL as backup if "cursor.com/settings" in self.browser.url: - print(f"{Fore.CYAN}{EMOJI['INFO']} Detected successful login{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.detected_successful_login') if self.translator else 'Detected successful login'}{Style.RESET_ALL}") except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Waiting for authentication... ({str(e)}){Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.waiting_for_authentication', error=str(e)) if self.translator else f'Waiting for authentication... ({str(e)})'}{Style.RESET_ALL}") time.sleep(check_interval) - print(f"{Fore.RED}{EMOJI['ERROR']} Authentication timeout{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_timeout') if self.translator else 'Authentication timeout'}{Style.RESET_ALL}") return None except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Error while waiting for authentication: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_waiting_for_authentication', error=str(e)) if self.translator else f'Error while waiting for authentication: {str(e)}'}{Style.RESET_ALL}") return None def handle_github_auth(self): @@ -466,7 +467,7 @@ class OAuthHandler: # Navigate to auth URL try: - print(f"{Fore.CYAN}{EMOJI['INFO']} Navigating to authentication page...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.navigating_to_authentication_page') if self.translator else 'Navigating to authentication page...'}{Style.RESET_ALL}") self.browser.get("https://authenticator.cursor.sh/sign-up") time.sleep(get_random_wait_time(self.config, 'page_load_wait')) @@ -490,21 +491,21 @@ class OAuthHandler: raise Exception("Could not find GitHub authentication button") # Click the button and wait for page load - print(f"{Fore.CYAN}{EMOJI['INFO']} Starting GitHub authentication...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_github_authentication') if self.translator else 'Starting GitHub authentication...'}{Style.RESET_ALL}") auth_btn.click() time.sleep(get_random_wait_time(self.config, 'page_load_wait')) # Wait for authentication to complete auth_info = self._wait_for_auth() if not auth_info: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.timeout')}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.timeout') if self.translator else 'Timeout'}{Style.RESET_ALL}") return False, None print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.success')}{Style.RESET_ALL}") return True, auth_info except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Authentication error: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_error', error=str(e)) if self.translator else f'Authentication error: {str(e)}'}{Style.RESET_ALL}") return False, None finally: try: @@ -566,23 +567,23 @@ class OAuthHandler: # Check if we're on account selection page if auth_type == "google" and "accounts.google.com" in self.browser.url: - alert_js = """ - alert('Please select your Google account manually to continue with Cursor authentication'); - """ + alert_message = self.translator.get('oauth.please_select_your_google_account_to_continue') if self.translator else 'Please select your Google account to continue with Cursor authentication' try: - self.browser.run_js(alert_js) + self.browser.run_js(f""" + alert('{alert_message}'); + """) except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Alert display failed: {str(e)}{Style.RESET_ALL}") - print(f"{Fore.CYAN}{EMOJI['INFO']} Please select your Google account manually to continue with Cursor authentication...{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.alert_display_failed', error=str(e)) if self.translator else f'Alert display failed: {str(e)}'}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.please_select_your_google_account_manually_to_continue_with_cursor_authentication') if self.translator else 'Please select your Google account manually to continue with Cursor authentication...'}{Style.RESET_ALL}") - print(f"{Fore.CYAN}{EMOJI['INFO']} Waiting for authentication to complete...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.waiting_for_authentication_to_complete') if self.translator else 'Waiting for authentication to complete...'}{Style.RESET_ALL}") # Wait for authentication to complete max_wait = 300 # 5 minutes start_time = time.time() last_url = self.browser.url - print(f"{Fore.CYAN}{EMOJI['WAIT']} Checking authentication status...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('oauth.checking_authentication_status') if self.translator else 'Checking authentication status...'}{Style.RESET_ALL}") while time.time() - start_time < max_wait: try: @@ -598,9 +599,9 @@ class OAuthHandler: token = value.split("%3A%3A")[-1] if token: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Authentication successful!{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.authentication_successful') if self.translator else 'Authentication successful!'}{Style.RESET_ALL}") # Navigate to settings page - print(f"{Fore.CYAN}{EMOJI['INFO']} Navigating to settings page...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.navigating_to_settings_page') if self.translator else 'Navigating to settings page...'}{Style.RESET_ALL}") self.browser.get("https://www.cursor.com/settings") time.sleep(3) # Wait for settings page to load @@ -609,9 +610,9 @@ class OAuthHandler: email_element = self.browser.ele("css:div[class='flex w-full flex-col gap-2'] div:nth-child(2) p:nth-child(2)") if email_element: actual_email = email_element.text - print(f"{Fore.CYAN}{EMOJI['INFO']} Found email: {actual_email}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_email', email=actual_email) if self.translator else f'Found email: {actual_email}'}{Style.RESET_ALL}") except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Could not find email: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_find_email', error=str(e)) if self.translator else f'Could not find email: {str(e)}'}{Style.RESET_ALL}") actual_email = "user@cursor.sh" # Check usage count @@ -619,11 +620,11 @@ class OAuthHandler: usage_element = self.browser.ele("css:div[class='flex flex-col gap-4 lg:flex-row'] div:nth-child(1) div:nth-child(1) span:nth-child(2)") if usage_element: usage_text = usage_element.text - print(f"{Fore.CYAN}{EMOJI['INFO']} Usage count: {usage_text}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.usage_count', usage=usage_text) if self.translator else f'Usage count: {usage_text}'}{Style.RESET_ALL}") # Check if account is expired if usage_text.strip() == "150 / 150": - print(f"{Fore.YELLOW}{EMOJI['INFO']} Account has reached maximum usage, deleting...{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.account_has_reached_maximum_usage', deleting='deleting') if self.translator else 'Account has reached maximum usage, deleting...'}{Style.RESET_ALL}") delete_js = """ function deleteAccount() { @@ -655,23 +656,23 @@ class OAuthHandler: print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Delete account result: {result}{Style.RESET_ALL}") # Navigate back to auth page and repeat authentication - print(f"{Fore.CYAN}{EMOJI['INFO']} Starting re-authentication process...{Style.RESET_ALL}") - print(f"{Fore.CYAN}{EMOJI['INFO']} Redirecting to authenticator.cursor.sh...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_re_authentication_process') if self.translator else 'Starting re-authentication process...'}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.redirecting_to_authenticator_cursor_sh') if self.translator else 'Redirecting to authenticator.cursor.sh...'}{Style.RESET_ALL}") # Explicitly navigate to the authentication page self.browser.get("https://authenticator.cursor.sh/sign-up") time.sleep(get_random_wait_time(self.config, 'page_load_wait')) # Call handle_google_auth again to repeat the entire process - print(f"{Fore.CYAN}{EMOJI['INFO']} Starting new Google authentication...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_new_google_authentication') if self.translator else 'Starting new Google authentication...'}{Style.RESET_ALL}") return self.handle_google_auth() except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Failed to delete account or re-authenticate: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_delete_account_or_re_authenticate', error=str(e)) if self.translator else f'Failed to delete account or re-authenticate: {str(e)}'}{Style.RESET_ALL}") else: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Account is still valid (Usage: {usage_text}){Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.account_is_still_valid', usage=usage_text) if self.translator else f'Account is still valid (Usage: {usage_text})'}{Style.RESET_ALL}") except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Could not find usage count: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_find_usage_count', error=str(e)) if self.translator else f'Could not find usage count: {str(e)}'}{Style.RESET_ALL}") # Remove the browser stay open prompt and input wait return True, {"email": actual_email, "token": token} @@ -679,7 +680,7 @@ class OAuthHandler: # Also check URL as backup current_url = self.browser.url if "cursor.com/settings" in current_url: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Already on settings page!{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.already_on_settings_page') if self.translator else 'Already on settings page!'}{Style.RESET_ALL}") time.sleep(1) cookies = self.browser.cookies() for cookie in cookies: @@ -695,9 +696,9 @@ class OAuthHandler: email_element = self.browser.ele("css:div[class='flex w-full flex-col gap-2'] div:nth-child(2) p:nth-child(2)") if email_element: actual_email = email_element.text - print(f"{Fore.CYAN}{EMOJI['INFO']} Found email: {actual_email}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_email', email=actual_email) if self.translator else f'Found email: {actual_email}'}{Style.RESET_ALL}") except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Could not find email: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_find_email', error=str(e)) if self.translator else f'Could not find email: {str(e)}'}{Style.RESET_ALL}") actual_email = "user@cursor.sh" # Check usage count @@ -705,11 +706,11 @@ class OAuthHandler: usage_element = self.browser.ele("css:div[class='flex flex-col gap-4 lg:flex-row'] div:nth-child(1) div:nth-child(1) span:nth-child(2)") if usage_element: usage_text = usage_element.text - print(f"{Fore.CYAN}{EMOJI['INFO']} Usage count: {usage_text}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.usage_count', usage=usage_text) if self.translator else f'Usage count: {usage_text}'}{Style.RESET_ALL}") # Check if account is expired if usage_text.strip() == "150 / 150": - print(f"{Fore.YELLOW}{EMOJI['INFO']} Account has reached maximum usage, deleting...{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.account_has_reached_maximum_usage', deleting='deleting') if self.translator else 'Account has reached maximum usage, deleting...'}{Style.RESET_ALL}") delete_js = """ function deleteAccount() { @@ -741,44 +742,44 @@ class OAuthHandler: print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Delete account result: {result}{Style.RESET_ALL}") # Navigate back to auth page and repeat authentication - print(f"{Fore.CYAN}{EMOJI['INFO']} Starting re-authentication process...{Style.RESET_ALL}") - print(f"{Fore.CYAN}{EMOJI['INFO']} Redirecting to authenticator.cursor.sh...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_re_authentication_process') if self.translator else 'Starting re-authentication process...'}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.redirecting_to_authenticator_cursor_sh') if self.translator else 'Redirecting to authenticator.cursor.sh...'}{Style.RESET_ALL}") # Explicitly navigate to the authentication page self.browser.get("https://authenticator.cursor.sh/sign-up") time.sleep(get_random_wait_time(self.config, 'page_load_wait')) # Call handle_google_auth again to repeat the entire process - print(f"{Fore.CYAN}{EMOJI['INFO']} Starting new Google authentication...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_new_google_authentication') if self.translator else 'Starting new Google authentication...'}{Style.RESET_ALL}") return self.handle_google_auth() except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Failed to delete account or re-authenticate: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_delete_account_or_re_authenticate', error=str(e)) if self.translator else f'Failed to delete account or re-authenticate: {str(e)}'}{Style.RESET_ALL}") else: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Account is still valid (Usage: {usage_text}){Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.account_is_still_valid', usage=usage_text) if self.translator else f'Account is still valid (Usage: {usage_text})'}{Style.RESET_ALL}") except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Could not find usage count: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_find_usage_count', error=str(e)) if self.translator else f'Could not find usage count: {str(e)}'}{Style.RESET_ALL}") # Remove the browser stay open prompt and input wait return True, {"email": actual_email, "token": token} elif current_url != last_url: - print(f"{Fore.CYAN}{EMOJI['INFO']} Page changed, checking auth...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.page_changed_checking_auth') if self.translator else 'Page changed, checking auth...'}{Style.RESET_ALL}") last_url = current_url time.sleep(get_random_wait_time(self.config, 'page_load_wait')) except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Status check error: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.status_check_error', error=str(e)) if self.translator else f'Status check error: {str(e)}'}{Style.RESET_ALL}") time.sleep(1) continue time.sleep(1) - print(f"{Fore.RED}{EMOJI['ERROR']} Authentication timeout{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_timeout') if self.translator else 'Authentication timeout'}{Style.RESET_ALL}") return False, None - print(f"{Fore.RED}{EMOJI['ERROR']} Authentication button not found{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_button_not_found') if self.translator else 'Authentication button not found'}{Style.RESET_ALL}") return False, None except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Authentication failed: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_failed', error=str(e)) if self.translator else f'Authentication failed: {str(e)}'}{Style.RESET_ALL}") return False, None finally: if self.browser: @@ -801,7 +802,7 @@ class OAuthHandler: time.sleep(1) # Debug cookie information - print(f"{Fore.CYAN}{EMOJI['INFO']} Found {len(cookies)} cookies{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_cookies', count=len(cookies)) if self.translator else f'Found {len(cookies)} cookies'}{Style.RESET_ALL}") email = None token = None @@ -816,12 +817,12 @@ class OAuthHandler: elif "%3A%3A" in value: token = value.split("%3A%3A")[-1] except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Token extraction error: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.token_extraction_error', error=str(e)) if self.translator else f'Token extraction error: {str(e)}'}{Style.RESET_ALL}") elif name == "cursor_email": email = cookie.get("value") if email and token: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Authentication successful - Email: {email}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.authentication_successful', email=email) if self.translator else f'Authentication successful - Email: {email}'}{Style.RESET_ALL}") return True, {"email": email, "token": token} else: missing = [] @@ -829,11 +830,11 @@ class OAuthHandler: missing.append("email") if not token: missing.append("token") - print(f"{Fore.RED}{EMOJI['ERROR']} Missing authentication data: {', '.join(missing)}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.missing_authentication_data', data=', '.join(missing)) if self.translator else f'Missing authentication data: {", ".join(missing)}'}{Style.RESET_ALL}") return False, None except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Failed to extract auth info: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_extract_auth_info', error=str(e)) if self.translator else f'Failed to extract auth info: {str(e)}'}{Style.RESET_ALL}") return False, None def _delete_current_account(self): @@ -868,14 +869,14 @@ class OAuthHandler: print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Delete account result: {result}{Style.RESET_ALL}") # Navigate back to auth page - print(f"{Fore.CYAN}{EMOJI['INFO']} Redirecting to authenticator.cursor.sh...{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.redirecting_to_authenticator_cursor_sh') if self.translator else 'Redirecting to authenticator.cursor.sh...'}{Style.RESET_ALL}") self.browser.get("https://authenticator.cursor.sh/sign-up") time.sleep(get_random_wait_time(self.config, 'page_load_wait')) return True except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} Failed to delete account: {str(e)}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_delete_account', error=str(e)) if self.translator else f'Failed to delete account: {str(e)}'}{Style.RESET_ALL}") return False def main(auth_type, translator=None): @@ -888,13 +889,13 @@ def main(auth_type, translator=None): handler = OAuthHandler(translator, auth_type) if auth_type.lower() == 'google': - print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('oauth.google_start')}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('oauth.google_start') if translator else 'Google start'}{Style.RESET_ALL}") success, auth_info = handler.handle_google_auth() elif auth_type.lower() == 'github': - print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('oauth.github_start')}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('oauth.github_start') if translator else 'Github start'}{Style.RESET_ALL}") success, auth_info = handler.handle_github_auth() else: - print(f"{Fore.RED}{EMOJI['ERROR']} Invalid authentication type{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('oauth.invalid_authentication_type') if translator else 'Invalid authentication type'}{Style.RESET_ALL}") return False if success and auth_info: @@ -905,13 +906,13 @@ def main(auth_type, translator=None): access_token=auth_info["token"], refresh_token=auth_info["token"] ): - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('oauth.auth_update_success')}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('oauth.auth_update_success') if translator else 'Auth update success'}{Style.RESET_ALL}") # Close the browser after successful authentication if handler.browser: handler.browser.quit() - print(f"{Fore.CYAN}{EMOJI['INFO']} Browser closed{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('oauth.browser_closed') if translator else 'Browser closed'}{Style.RESET_ALL}") return True else: - print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('oauth.auth_update_failed')}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('oauth.auth_update_failed') if translator else 'Auth update failed'}{Style.RESET_ALL}") return False \ No newline at end of file