diff --git a/.env b/.env index d88c350..f44a1bc 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -version=1.4.01 -VERSION=1.4.01 +version=1.4.03 +VERSION=1.4.03 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 39fe116..263f622 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -63,7 +63,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: CursorFreeVIP_${{ env.VERSION }}_windows.exe - path: dist/* + path: dist/CursorFreeVIP_${{ env.VERSION }}_windows.exe build-macos-arm64: needs: create-tag @@ -90,12 +90,13 @@ jobs: - name: Build MacOS ARM executable run: | pyinstaller build.spec + mv "dist/CursorFreeVIP_${{ env.VERSION }}_mac" "dist/CursorFreeVIP_${{ env.VERSION }}_mac_arm64" - name: Upload MacOS ARM artifact uses: actions/upload-artifact@v4 with: name: CursorFreeVIP_${{ env.VERSION }}_mac_arm64 - path: dist/* + path: dist/CursorFreeVIP_${{ env.VERSION }}_mac_arm64 build-linux: needs: create-tag @@ -120,14 +121,18 @@ jobs: pip install -r requirements.txt - name: Build Linux executable + env: + VERSION: ${{ env.VERSION }} run: | pyinstaller build.spec + echo "Contents of dist directory:" + ls -la dist/ - name: Upload Linux artifact uses: actions/upload-artifact@v4 with: name: CursorFreeVIP_${{ env.VERSION }}_linux - path: dist/* + path: dist/CursorFreeVIP_${{ env.VERSION }}_linux build-macos-intel: @@ -155,14 +160,16 @@ jobs: - name: Build MacOS Intel executable env: TARGET_ARCH: 'x86_64' + VERSION: ${{ env.VERSION }} run: | arch -x86_64 python3 -m PyInstaller build.spec + mv "dist/CursorFreeVIP_${{ env.VERSION }}_mac" "dist/CursorFreeVIP_${{ env.VERSION }}_mac_intel" - name: Upload MacOS Intel artifact uses: actions/upload-artifact@v4 with: name: CursorFreeVIP_${{ env.VERSION }}_mac_intel - path: dist/* + path: dist/CursorFreeVIP_${{ env.VERSION }}_mac_intel create-release: @@ -182,24 +189,20 @@ jobs: - name: Prepare release files run: | cd artifacts - # 重命名文件为最终的可执行文件名 - mv CursorFreeVIP_${{ env.VERSION }}_windows.exe/CursorFreeVIP.exe CursorFreeVIP_${{ env.VERSION }}_windows.exe - mv CursorFreeVIP_${{ env.VERSION }}_mac_arm64/CursorFreeVIP CursorFreeVIP_${{ env.VERSION }}_mac_arm64 - mv CursorFreeVIP_${{ env.VERSION }}_linux/CursorFreeVIP CursorFreeVIP_${{ env.VERSION }}_linux - mv CursorFreeVIP_${{ env.VERSION }}_mac_intel/CursorFreeVIP CursorFreeVIP_${{ env.VERSION }}_mac_intel - # 删除空目录 - rm -rf */ + echo "Contents of artifacts directory:" ls -la - + echo "Contents of subdirectories:" + ls -la */ + - name: Create Release uses: softprops/action-gh-release@v1 with: tag_name: v${{ env.VERSION }} files: | - artifacts/CursorFreeVIP_${{ env.VERSION }}_windows.exe - artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_arm64 - artifacts/CursorFreeVIP_${{ env.VERSION }}_linux - artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_intel + artifacts/CursorFreeVIP_${{ env.VERSION }}_windows.exe/CursorFreeVIP_${{ env.VERSION }}_windows.exe + artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_arm64/CursorFreeVIP_${{ env.VERSION }}_mac_arm64 + artifacts/CursorFreeVIP_${{ env.VERSION }}_linux/CursorFreeVIP_${{ env.VERSION }}_linux + artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_intel/CursorFreeVIP_${{ env.VERSION }}_mac_intel draft: false prerelease: false env: diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..82438eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +cursor_accounts.txt +/venv +/__pycache__ diff --git a/CHANGELOG.md b/CHANGELOG.md index 805fd55..e02e194 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## v1.4.03 + +1. Switch to API-based Registration System | 改用API註冊系統替代瀏覽器操作 +2. Add Support for Latest Cursor Version | 增加支持最新版本Cursor +3. Enhance Translation System | 優化多語言翻譯系統 +4. Add Database Connection Status Messages | 增加數據庫連接狀態提示 +5. Improve Error Handling for Database Operations | 改進數據庫操作的錯誤處理 +6. Add New API Integration | 新增API集成 +7. Optimize Performance and Stability | 優化性能和穩定性 + ## v1.4.01 1. Add Disable Cursor Auto Upgrade | 增加禁用Cursor自動升級 diff --git a/README.md b/README.md index 517934d..5e6d4fa 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ [![Download](https://img.shields.io/github/downloads/yeongpin/cursor-free-vip/total?style=flat-square&logo=github&color=52c41a)](https://github.com/yeongpin/cursor-free-vip/releases/latest)

-

Support Latest 0.45.16 Version | 支持最新0.45.16版本

+

Support Latest 0.46.3 Version | 支持最新0.46.3本

This is a tool to automatically register , support Windows and macOS systems, complete Auth verification, and reset Cursor's configuration. diff --git a/cursor_auth.py b/cursor_auth.py index 4df112d..c2a2bbe 100644 --- a/cursor_auth.py +++ b/cursor_auth.py @@ -31,6 +31,23 @@ class CursorAuth: "~/Library/Application Support/Cursor/User/globalStorage/state.vscdb" ) + # 检查数据库文件是否存在 + if not os.path.exists(self.db_path): + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.db_not_found', path=self.db_path)}{Style.RESET_ALL}") + return + + # 检查文件权限 + if not os.access(self.db_path, os.R_OK | os.W_OK): + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.db_permission_error')}{Style.RESET_ALL}") + return + + try: + self.conn = sqlite3.connect(self.db_path) + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('auth.connected_to_database')}{Style.RESET_ALL}") + except sqlite3.Error as e: + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.db_connection_error', error=str(e))}{Style.RESET_ALL}") + return + def update_auth(self, email=None, access_token=None, refresh_token=None): conn = None try: diff --git a/cursor_register.py b/cursor_register.py index 05093b2..4623fd8 100644 --- a/cursor_register.py +++ b/cursor_register.py @@ -76,10 +76,9 @@ class CursorRegistration: print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.email_create_failed')}{Style.RESET_ALL}") return False - # 保存邮箱地址和浏览器实例 + # 保存邮箱地址 self.email_address = email_address - self.email_tab = self.temp_email # 传递 NewTempEmail 实例而不是 page - self.controller = BrowserControl(self.temp_email.page, self.translator) + self.email_tab = self.temp_email # 传递 NewTempEmail 实例 return True diff --git a/locales/en.json b/locales/en.json index 8b50b00..e0f8905 100644 --- a/locales/en.json +++ b/locales/en.json @@ -2,17 +2,17 @@ "menu": { "title": "Available Options", "exit": "Exit Program", - "reset": "Reset Machine Manual", - "register": "Register Cursor", - "register_manual": "Register Cursor With Manual Email", - "quit": "Quit Cursor", - "select_language": "Select Language", - "input_choice": "Enter your choice ({choices})", - "invalid_choice": "Invalid choice. Please try again", - "program_terminated": "Program terminated by user", - "error_occurred": "An error occurred: {error}", + "reset": "Reset Machine ID", + "register": "Register New Cursor Account", + "register_manual": "Register Cursor with Custom Email", + "quit": "Close Cursor Application", + "select_language": "Change Language", + "input_choice": "Please enter your choice ({choices})", + "invalid_choice": "Invalid selection. Please enter a number from {choices}", + "program_terminated": "Program was terminated by user", + "error_occurred": "An error occurred: {error}. Please try again", "press_enter": "Press Enter to Exit", - "disable_auto_update": "Disable Cursor Auto Update" + "disable_auto_update": "Disable Cursor Auto-Update" }, "languages": { "en": "English", @@ -68,21 +68,21 @@ }, "register": { "title": "Cursor Registration Tool", - "start": "Starting Registration Process", - "handling_turnstile": "Handling Turnstile", - "retry_verification": "Retry Verification", - "detect_turnstile": "Detect Turnstile", - "verification_success": "Verification Success", - "starting_browser": "Starting Browser", - "form_success": "Form Success", - "browser_started": "Browser Started", - "waiting_for_second_verification": "Waiting for Second Verification", - "waiting_for_verification_code": "Waiting for Verification Code", - "password_success": "Password Set Successfully", - "password_error": "Password Set Failed: {error}", - "waiting_for_page_load": "Waiting for Page Load", - "first_verification_passed": "First Verification Passed", - "mailbox": "Successfully Entered Mailbox", + "start": "Starting registration process...", + "handling_turnstile": "Processing security verification...", + "retry_verification": "Retrying verification...", + "detect_turnstile": "Checking security verification...", + "verification_success": "Security verification successful", + "starting_browser": "Opening browser...", + "form_success": "Form submitted successfully", + "browser_started": "Browser opened successfully", + "waiting_for_second_verification": "Waiting for email verification...", + "waiting_for_verification_code": "Waiting for verification code...", + "password_success": "Password set successfully", + "password_error": "Could not set password: {error}. Please try again", + "waiting_for_page_load": "Loading page...", + "first_verification_passed": "Initial verification successful", + "mailbox": "Successfully accessed email inbox", "register_start": "Start Register", "form_submitted": "Form Submitted, Start Verification...", "filling_form": "Fill Form", @@ -145,7 +145,10 @@ "database_connection_closed": "Database Connection Closed", "database_updated_successfully": "Database Updated Successfully", "connected_to_database": "Connected to Database", - "updating_pair": "Updating Key-Value Pair" + "updating_pair": "Updating Key-Value Pair", + "db_not_found": "Database file not found at: {path}", + "db_permission_error": "Cannot access database file. Please check permissions", + "db_connection_error": "Failed to connect to database: {error}" }, "control": { "generate_email": "Generating New Email", @@ -182,7 +185,7 @@ }, "email": { "starting_browser": "Starting Browser", - "visiting_site": "Visiting smailpro.com", + "visiting_site": "Visiting mail.tm", "create_success": "Email Created Successfully", "create_failed": "Failed to Create Email", "create_error": "Email Creation Error: {error}", diff --git a/locales/zh_cn.json b/locales/zh_cn.json index 0a0d536..422356a 100644 --- a/locales/zh_cn.json +++ b/locales/zh_cn.json @@ -3,14 +3,14 @@ "title": "可用选项", "exit": "退出程序", "reset": "重置机器标识", - "register": "注册 Cursor", - "register_manual": "手动指定邮箱注册 Cursor", - "quit": "退出 Cursor", - "select_language": "选择语言", - "input_choice": "输入选择 ({choices})", - "invalid_choice": "无效选择,请重试", - "program_terminated": "程序被用户终止", - "error_occurred": "发生错误: {error}", + "register": "注册新 Cursor 账号", + "register_manual": "使用自定义邮箱注册", + "quit": "关闭 Cursor 应用", + "select_language": "更改语言", + "input_choice": "请输入您的选择 ({choices})", + "invalid_choice": "选择无效,请输入 {choices} 范围内的数字", + "program_terminated": "程序已被用户终止", + "error_occurred": "发生错误:{error},请重试", "press_enter": "按回车键退出", "disable_auto_update": "禁用 Cursor 自动更新" }, @@ -68,25 +68,25 @@ }, "register": { "title": "Cursor 注册工具", - "start": "开始注册流程", - "browser_started": "浏览器已启动", - "password_success": "密码设置完成", - "password_error": "密码设置失败: {error}", - "waiting_for_page_load": "等待页面加载", - "mailbox": "成功进入邮箱", - "waiting_for_second_verification": "等待第二阶段验证", - "waiting_for_verification_code": "等待验证码", - "first_verification_passed": "第一阶段验证通过", + "start": "正在启动注册流程...", + "browser_started": "浏览器已成功打开", + "password_success": "密码设置成功", + "password_error": "无法设置密码:{error},请重试", + "waiting_for_page_load": "页面加载中...", + "mailbox": "已成功访问邮箱", + "waiting_for_second_verification": "等待邮箱验证...", + "waiting_for_verification_code": "等待验证码...", + "first_verification_passed": "初始验证通过", "register_start": "开始注册流程", "form_submitted": "表单已提交,开始验证...", "filling_form": "填写注册信息", "visiting_url": "访问URL", "basic_info": "基本信息提交完成", - "handling_turnstile": "处理 Turnstile 验证", - "retry_verification": "重试验证", - "detect_turnstile": "检测 Turnstile 验证", - "verification_success": "验证成功", - "starting_browser": "启动浏览器", + "handling_turnstile": "正在处理安全验证...", + "retry_verification": "正在重试验证...", + "detect_turnstile": "正在检查安全验证...", + "verification_success": "安全验证通过", + "starting_browser": "正在打开浏览器...", "form_success": "表单提交成功", "handle_turnstile": "处理 Turnstile 验证", "no_turnstile": "未检测到 Turnstile 验证", @@ -144,7 +144,10 @@ "connected_to_database": "已连接到数据库", "database_updated_successfully": "数据库更新成功", "database_connection_closed": "数据库连接已关闭", - "updating_pair": "更新键值对" + "updating_pair": "更新键值对", + "db_not_found": "未找到数据库文件:{path}", + "db_permission_error": "无法访问数据库文件,请检查权限", + "db_connection_error": "连接数据库失败:{error}" }, "control": { "generate_email": "生成新邮箱", @@ -179,7 +182,7 @@ }, "email": { "starting_browser": "启动浏览器", - "visiting_site": "访问 smailpro.com", + "visiting_site": "访问 mail.tm", "create_success": "邮箱创建成功", "create_failed": "邮箱创建失败", "create_error": "邮箱创建错误: {error}", diff --git a/locales/zh_tw.json b/locales/zh_tw.json index cb260aa..5fc0883 100644 --- a/locales/zh_tw.json +++ b/locales/zh_tw.json @@ -1,18 +1,18 @@ { "menu": { "title": "可用選項", - "exit": "退出程序", - "reset": "重置機器標識", - "register": "註冊 Cursor", - "register_manual": "手動指定郵箱註冊 Cursor", - "quit": "退出 Cursor", - "select_language": "選擇語言", - "input_choice": "輸入選擇 ({choices})", - "invalid_choice": "無效選擇,請重試", - "program_terminated": "程序被用戶終止", - "error_occurred": "發生錯誤: {error}", - "press_enter": "按回車鍵退出", - "disable_auto_update": "禁用 Cursor 自動更新" + "exit": "退出程式", + "reset": "重置機器識別碼", + "register": "註冊新 Cursor 帳號", + "register_manual": "使用自訂郵箱註冊", + "quit": "關閉 Cursor 應用程式", + "select_language": "變更語言", + "input_choice": "請輸入您的選擇 ({choices})", + "invalid_choice": "選擇無效,請輸入 {choices} 範圍內的數字", + "program_terminated": "程式已被使用者終止", + "error_occurred": "發生錯誤:{error},請重試", + "press_enter": "按返回鍵退出", + "disable_auto_update": "停用 Cursor 自動更新" }, "languages": { "en": "English", @@ -68,17 +68,24 @@ }, "register": { "title": "Cursor 註冊工具", - "start": "開始註冊流程", - "mailbox": "成功進入郵箱", - "browser_started": "瀏覽器已啟動", - "waiting_for_page_load": "等待頁面加載", - "password_success": "密碼設置完成", - "password_error": "密碼設置失敗: {error}", + "start": "正在啟動註冊流程...", + "handling_turnstile": "正在處理安全驗證...", + "retry_verification": "正在重試驗證...", + "detect_turnstile": "正在檢查安全驗證...", + "verification_success": "安全驗證通過", + "starting_browser": "正在開啟瀏覽器...", + "form_success": "表單提交成功", + "browser_started": "瀏覽器已成功開啟", + "waiting_for_second_verification": "等待郵箱驗證...", + "waiting_for_verification_code": "等待驗證碼...", + "password_success": "密碼設定成功", + "password_error": "無法設定密碼:{error},請重試", + "waiting_for_page_load": "頁面載入中...", + "first_verification_passed": "初始驗證通過", + "mailbox": "已成功存取郵箱", "visiting_url": "訪問URL", - "first_verification_passed": "第一階段驗證通過", "register_start": "開始註冊流程", "form_submitted": "表單已提交,開始驗證...", - "waiting_for_second_verification": "等待第二階段驗證", "filling_form": "填寫註冊信息", "basic_info": "基本信息提交完成", "handle_turnstile": "處理 Turnstile 驗證", @@ -86,31 +93,6 @@ "turnstile_passed": "驗證通過", "verification_start": "開始獲取驗證碼", "waiting_for_verification_code": "等待驗證碼", - "handling_turnstile": "處理 Turnstile 驗證", - "retry_verification": "重試驗證", - "detect_turnstile": "檢測 Turnstile 驗證", - "verification_success": "驗證成功", - "starting_browser": "啟動瀏覽器", - "form_success": "表單提交成功", - "verification_timeout": "獲取驗證碼超時", - "verification_not_found": "未找到驗證碼", - "try_get_code": "第 {attempt} 次嘗試獲取驗證碼 | 剩餘時間: {time}秒", - "get_account": "獲取賬戶信息", - "get_token": "獲取 Cursor Session Token", - "token_success": "Token 獲取成功", - "token_attempt": "第 {attempt} 次嘗試未獲取到 Token,{time}秒後重試", - "token_max_attempts": "已達到最大嘗試次數({max}),獲取 Token 失敗", - "token_failed": "獲取 Token 失敗: {error}", - "account_error": "獲取賬戶信息失敗: {error}", - "press_enter": "按回車鍵退出", - "browser_start": "正在啟動瀏覽器", - "open_mailbox": "正在打開郵箱頁面", - "email_error": "獲取郵箱地址失敗", - "setup_error": "郵箱設置出錯: {error}", - "start_getting_verification_code": "開始獲取驗證碼,將在60秒內嘗試...", - "get_verification_code_timeout": "獲取驗證碼超時", - "get_verification_code_success": "成功獲取驗證碼", - "try_get_verification_code": "第 {attempt} 次嘗試未獲取到驗證碼,剩餘時間: {remaining_time}秒", "verification_code_filled": "驗證碼填寫完成", "login_success_and_jump_to_settings_page": "成功登錄並跳轉到設置頁面", "detect_login_page": "檢測到登錄頁面,開始登錄...", @@ -144,7 +126,10 @@ "connected_to_database": "已連接到數據庫", "database_updated_successfully": "數據庫更新成功", "database_connection_closed": "數據庫連接已關閉", - "updating_pair": "更新鍵值對" + "updating_pair": "更新鍵值對", + "db_not_found": "未找到數據庫文件:{path}", + "db_permission_error": "無法訪問數據庫文件,請檢查權限", + "db_connection_error": "連接數據庫失敗:{error}" }, "control": { "generate_email": "生成新郵箱", @@ -179,7 +164,7 @@ }, "email": { "starting_browser": "啟動瀏覽器", - "visiting_site": "訪問 smailpro.com", + "visiting_site": "訪問 mail.tm", "create_success": "郵箱創建成功", "create_failed": "郵箱創建失敗", "create_error": "郵箱創建錯誤: {error}", diff --git a/main.py b/main.py index 05335d9..a2c8b31 100644 --- a/main.py +++ b/main.py @@ -25,43 +25,71 @@ EMOJI = { class Translator: def __init__(self): - self.current_language = 'zh_tw' # 默认语言 + self.current_language = 'en' # Default language self.translations = {} + self.fallback_language = 'en' # Fallback language if translation is missing self.load_translations() def load_translations(self): - """加载所有可用的翻译""" - locales_dir = os.path.join(os.path.dirname(__file__), 'locales') - if hasattr(sys, '_MEIPASS'): - locales_dir = os.path.join(sys._MEIPASS, 'locales') + """Load all available translations""" + try: + locales_dir = os.path.join(os.path.dirname(__file__), 'locales') + if hasattr(sys, '_MEIPASS'): + locales_dir = os.path.join(sys._MEIPASS, 'locales') - for file in os.listdir(locales_dir): - if file.endswith('.json'): - lang_code = file[:-5] # 移除 .json - with open(os.path.join(locales_dir, file), 'r', encoding='utf-8') as f: - self.translations[lang_code] = json.load(f) + if not os.path.exists(locales_dir): + print(f"{Fore.RED}{EMOJI['ERROR']} Locales directory not found{Style.RESET_ALL}") + return + + for file in os.listdir(locales_dir): + if file.endswith('.json'): + lang_code = file[:-5] # Remove .json + try: + with open(os.path.join(locales_dir, file), 'r', encoding='utf-8') as f: + self.translations[lang_code] = json.load(f) + except (json.JSONDecodeError, UnicodeDecodeError) as e: + print(f"{Fore.RED}{EMOJI['ERROR']} Error loading {file}: {e}{Style.RESET_ALL}") + continue + except Exception as e: + print(f"{Fore.RED}{EMOJI['ERROR']} Failed to load translations: {e}{Style.RESET_ALL}") def get(self, key, **kwargs): - """获取翻译文本""" + """Get translated text with fallback support""" + try: + # Try current language + result = self._get_translation(self.current_language, key) + if result == key and self.current_language != self.fallback_language: + # Try fallback language if translation not found + result = self._get_translation(self.fallback_language, key) + return result.format(**kwargs) if kwargs else result + except Exception: + return key + + def _get_translation(self, lang_code, key): + """Get translation for a specific language""" try: keys = key.split('.') - value = self.translations.get(self.current_language, {}) + value = self.translations.get(lang_code, {}) for k in keys: if isinstance(value, dict): value = value.get(k, key) else: - return key # 如果中間值不是字典,返回原始key - return value.format(**kwargs) if kwargs else value + return key + return value except Exception: - return key # 出現任何錯誤時返回原始key + return key def set_language(self, lang_code): - """设置当前语言""" + """Set current language with validation""" if lang_code in self.translations: self.current_language = lang_code return True return False + def get_available_languages(self): + """Get list of available languages""" + return list(self.translations.keys()) + # 创建翻译器实例 translator = Translator() @@ -79,25 +107,26 @@ def print_menu(): print(f"{Fore.YELLOW}{'─' * 40}{Style.RESET_ALL}") def select_language(): - """语言选择菜单""" + """Language selection menu""" print(f"\n{Fore.CYAN}{EMOJI['LANG']} {translator.get('menu.select_language')}:{Style.RESET_ALL}") print(f"{Fore.YELLOW}{'─' * 40}{Style.RESET_ALL}") - languages = translator.get('languages') - for i, (code, name) in enumerate(languages.items()): - print(f"{Fore.GREEN}{i}{Style.RESET_ALL}. {name}") + languages = translator.get_available_languages() + for i, lang in enumerate(languages): + lang_name = translator.get(f"languages.{lang}") + print(f"{Fore.GREEN}{i}{Style.RESET_ALL}. {lang_name}") try: - choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices='0-' + str(len(languages)-1))}: {Style.RESET_ALL}") + choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices=f'0-{len(languages)-1}')}: {Style.RESET_ALL}") if choice.isdigit() and 0 <= int(choice) < len(languages): - lang_code = list(languages.keys())[int(choice)] - translator.set_language(lang_code) + translator.set_language(languages[int(choice)]) return True + else: + print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}") + return False except (ValueError, IndexError): - pass - - print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}") - return False + print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}") + return False def main(): print_logo() @@ -151,4 +180,4 @@ def main(): input(f"{EMOJI['INFO']} {translator.get('menu.press_enter')}...{Style.RESET_ALL}") if __name__ == "__main__": - main() \ No newline at end of file + main() \ No newline at end of file diff --git a/new_tempemail.py b/new_tempemail.py index cdca8b9..25c5b05 100644 --- a/new_tempemail.py +++ b/new_tempemail.py @@ -3,6 +3,9 @@ import time import os import sys from colorama import Fore, Style, init +import requests +import random +import string # 初始化 colorama init() @@ -10,95 +13,73 @@ init() class NewTempEmail: def __init__(self, translator=None): self.translator = translator - self.page = None - self.setup_browser() + # Randomly choose between mail.tm and mail.gw + self.services = [ + {"name": "mail.tm", "api_url": "https://api.mail.tm"}, + {"name": "mail.gw", "api_url": "https://api.mail.gw"} + ] + self.selected_service = random.choice(self.services) + self.api_url = self.selected_service["api_url"] + self.token = None + self.email = None + self.password = None - def get_extension_block(self): - """获取插件路径""" - root_dir = os.getcwd() - extension_path = os.path.join(root_dir, "PBlock") + def _generate_credentials(self): + """生成随机用户名和密码""" + username = ''.join(random.choices(string.ascii_lowercase + string.digits, k=10)) + password = ''.join(random.choices(string.ascii_letters + string.digits + string.punctuation, k=12)) + return username, password - if hasattr(sys, "_MEIPASS"): - extension_path = os.path.join(sys._MEIPASS, "PBlock") - - if not os.path.exists(extension_path): - raise FileNotFoundError(f"插件不存在: {extension_path}") - - return extension_path - - def setup_browser(self): - """设置浏览器""" - try: - if self.translator: - print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.starting_browser')}{Style.RESET_ALL}") - else: - print(f"{Fore.CYAN}ℹ️ 正在启动浏览器...{Style.RESET_ALL}") - - # 创建浏览器选项 - co = ChromiumOptions() - co.set_argument("--headless=new") - - co.auto_port() # 自动设置端口 - - # 加载 uBlock 插件 - try: - extension_path = self.get_extension_block() - co.set_argument("--allow-extensions-in-incognito") - co.add_extension(extension_path) - except Exception as e: - if self.translator: - print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.extension_load_error')}: {str(e)}{Style.RESET_ALL}") - else: - print(f"{Fore.YELLOW}⚠️ 加载插件失败: {str(e)}{Style.RESET_ALL}") - - self.page = ChromiumPage(co) - return True - except Exception as e: - if self.translator: - 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}") - return False - def create_email(self): """创建临时邮箱""" try: if self.translator: - print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.visiting_site')}{Style.RESET_ALL}") + print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.visiting_site').replace('mail.tm', self.selected_service['name'])}{Style.RESET_ALL}") else: - print(f"{Fore.CYAN}ℹ️ 正在访问 smailpro.com...{Style.RESET_ALL}") + print(f"{Fore.CYAN}ℹ️ 正在访问 {self.selected_service['name']}...{Style.RESET_ALL}") - # 访问网站 - self.page.get("https://smailpro.com/") - time.sleep(2) - - # 点击创建邮箱按钮 - create_button = self.page.ele('xpath://button[@title="Create temporary email"]') - if create_button: - create_button.click() - time.sleep(1) + # 获取可用域名列表 + domains_response = requests.get(f"{self.api_url}/domains") + if domains_response.status_code != 200: + raise Exception("Failed to get available domains") - # 点击弹窗中的 Create 按钮 - modal_create_button = self.page.ele('xpath://button[contains(text(), "Create")]') - if modal_create_button: - modal_create_button.click() - time.sleep(2) - - # 获取邮箱地址 - 修改选择器 - email_div = self.page.ele('xpath://div[@class="text-base sm:text-lg md:text-xl text-gray-700"]') - if email_div: - email = email_div.text.strip() - if '@' in email: # 验证是否是有效的邮箱地址 - if self.translator: - print(f"{Fore.GREEN}✅ {self.translator.get('email.create_success')}: {email}{Style.RESET_ALL}") - else: - print(f"{Fore.GREEN}✅ 创建邮箱成功: {email}{Style.RESET_ALL}") - return email + domains = domains_response.json()["hydra:member"] + if not domains: + raise Exception("No available domains") + + # 生成随机用户名和密码 + username, password = self._generate_credentials() + self.password = password + + # 创建邮箱账户 + email = f"{username}@{domains[0]['domain']}" + account_data = { + "address": email, + "password": password + } + + create_response = requests.post(f"{self.api_url}/accounts", json=account_data) + if create_response.status_code != 201: + raise Exception("Failed to create account") + + # 获取访问令牌 + token_data = { + "address": email, + "password": password + } + + token_response = requests.post(f"{self.api_url}/token", json=token_data) + if token_response.status_code != 200: + raise Exception("Failed to get access token") + + self.token = token_response.json()["token"] + self.email = email + if self.translator: - print(f"{Fore.RED}❌ {self.translator.get('email.create_failed')}{Style.RESET_ALL}") + print(f"{Fore.GREEN}✅ {self.translator.get('email.create_success')}: {email}{Style.RESET_ALL}") else: - print(f"{Fore.RED}❌ 创建邮箱失败{Style.RESET_ALL}") - return None + print(f"{Fore.GREEN}✅ 创建邮箱成功: {email}{Style.RESET_ALL}") + return email except Exception as e: if self.translator: @@ -120,11 +101,11 @@ class NewTempEmail: else: print(f"{Fore.CYAN}🔄 正在刷新邮箱...{Style.RESET_ALL}") - # 点击刷新按钮 - refresh_button = self.page.ele('xpath://button[@id="refresh"]') - if refresh_button: - refresh_button.click() - time.sleep(2) # 等待刷新完成 + # 使用 API 获取最新邮件 + headers = {"Authorization": f"Bearer {self.token}"} + response = requests.get(f"{self.api_url}/messages", headers=headers) + + if response.status_code == 200: if self.translator: print(f"{Fore.GREEN}✅ {self.translator.get('email.refresh_success')}{Style.RESET_ALL}") else: @@ -132,9 +113,9 @@ class NewTempEmail: return True if self.translator: - print(f"{Fore.RED}❌ {self.translator.get('email.refresh_button_not_found')}{Style.RESET_ALL}") + print(f"{Fore.RED}❌ {self.translator.get('email.refresh_failed')}{Style.RESET_ALL}") else: - print(f"{Fore.RED}❌ 未找到刷新按钮{Style.RESET_ALL}") + print(f"{Fore.RED}❌ 刷新邮箱失败{Style.RESET_ALL}") return False except Exception as e: @@ -147,17 +128,24 @@ class NewTempEmail: def check_for_cursor_email(self): """检查是否有 Cursor 的验证邮件""" try: - # 查找验证邮件 - 使用更精确的选择器 - email_div = self.page.ele('xpath://div[contains(@class, "p-2") and contains(@class, "cursor-pointer") and contains(@class, "bg-white") and contains(@class, "shadow") and .//b[text()="no-reply@cursor.sh"] and .//span[text()="Verify your email address"]]') - if email_div: - if self.translator: - print(f"{Fore.GREEN}✅ {self.translator.get('email.verification_found')}{Style.RESET_ALL}") - else: - print(f"{Fore.GREEN}✅ 找到验证邮件{Style.RESET_ALL}") - # 使用 JavaScript 点击元素 - self.page.run_js('arguments[0].click()', email_div) - time.sleep(2) # 等待邮件内容加载 - return True + # 使用 API 获取邮件列表 + headers = {"Authorization": f"Bearer {self.token}"} + response = requests.get(f"{self.api_url}/messages", headers=headers) + + if response.status_code == 200: + messages = response.json()["hydra:member"] + for message in messages: + if message["from"]["address"] == "no-reply@cursor.sh" and "Verify your email address" in message["subject"]: + # 获取邮件内容 + message_id = message["id"] + message_response = requests.get(f"{self.api_url}/messages/{message_id}", headers=headers) + if message_response.status_code == 200: + if self.translator: + print(f"{Fore.GREEN}✅ {self.translator.get('email.verification_found')}{Style.RESET_ALL}") + else: + print(f"{Fore.GREEN}✅ 找到验证邮件{Style.RESET_ALL}") + return True + if self.translator: print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.verification_not_found')}{Style.RESET_ALL}") else: @@ -174,16 +162,33 @@ class NewTempEmail: def get_verification_code(self): """获取验证码""" try: - # 查找验证码元素 - code_element = self.page.ele('xpath://td//div[contains(@style, "font-size:28px") and contains(@style, "letter-spacing:2px")]') - if code_element: - code = code_element.text.strip() - if code.isdigit() and len(code) == 6: - if self.translator: - print(f"{Fore.GREEN}✅ {self.translator.get('email.verification_code_found')}: {code}{Style.RESET_ALL}") - else: - print(f"{Fore.GREEN}✅ 获取验证码成功: {code}{Style.RESET_ALL}") - return code + # 使用 API 获取邮件列表 + headers = {"Authorization": f"Bearer {self.token}"} + response = requests.get(f"{self.api_url}/messages", headers=headers) + + if response.status_code == 200: + messages = response.json()["hydra:member"] + for message in messages: + if message["from"]["address"] == "no-reply@cursor.sh" and "Verify your email address" in message["subject"]: + # 获取邮件内容 + message_id = message["id"] + message_response = requests.get(f"{self.api_url}/messages/{message_id}", headers=headers) + + if message_response.status_code == 200: + # 从邮件内容中提取验证码 + email_content = message_response.json()["text"] + # 查找6位数字验证码 + import re + code_match = re.search(r'\b\d{6}\b', email_content) + + if code_match: + code = code_match.group(0) + if self.translator: + print(f"{Fore.GREEN}✅ {self.translator.get('email.verification_code_found')}: {code}{Style.RESET_ALL}") + else: + print(f"{Fore.GREEN}✅ 获取验证码成功: {code}{Style.RESET_ALL}") + return code + if self.translator: print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.verification_code_not_found')}{Style.RESET_ALL}") else: @@ -223,4 +228,4 @@ def main(translator=None): temp_email.close() if __name__ == "__main__": - main() \ No newline at end of file + main() \ No newline at end of file