mirror of
https://github.com/yeongpin/cursor-free-vip.git
synced 2025-04-24 08:25:23 +00:00
Merge pull request #94 from UntaDotMy/main
feat: Add support for Cursor v0.46.X and improve email service
This commit is contained in:
commit
4c91525082
35
.github/workflows/build.yml
vendored
35
.github/workflows/build.yml
vendored
@ -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:
|
||||
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
cursor_accounts.txt
|
||||
/venv
|
||||
/__pycache__
|
10
CHANGELOG.md
10
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自動升級
|
||||
|
@ -12,7 +12,7 @@
|
||||
[](https://github.com/yeongpin/cursor-free-vip/releases/latest)
|
||||
|
||||
</p>
|
||||
<h4>Support Latest 0.45.16 Version | 支持最新0.45.16版本</h4>
|
||||
<h4>Support Latest 0.46.3 Version | 支持最新0.46.3本</h4>
|
||||
|
||||
This is a tool to automatically register , support Windows and macOS systems, complete Auth verification, and reset Cursor's configuration.
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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}",
|
||||
|
@ -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}",
|
||||
|
@ -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}",
|
||||
|
85
main.py
85
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()
|
||||
main()
|
219
new_tempemail.py
219
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()
|
||||
main()
|
Loading…
x
Reference in New Issue
Block a user