Compare commits

...

51 Commits

Author SHA1 Message Date
Pin Studios
2bdcc2f633 chore: Bump version to 1.6.01 2025-03-06 12:19:26 +08:00
Pin Studios
4aabe2e403 chore: Bump version to 1.5.04 and improve system compatibility
- Update version in .env file to 1.5.04
- Add Mac-specific run_venv script to .gitignore
- Enhance Cursor Auth platform detection with more precise sys.platform checks
- Add maximum retry mechanism for email creation
- Improve error handling and platform support in cursor_auth.py
2025-03-06 12:18:55 +08:00
yeongpin
005aa2cd95 feat: Improve Version Update Mechanism with Robust Error Handling
- Enhance GitHub API version check with proper headers and timeout
- Add comprehensive error handling for version retrieval
- Implement more reliable update script download and execution
- Improve cross-platform update process with better error reporting
- Add fallback mechanisms for network and update failures
2025-03-06 11:18:21 +08:00
yeongpin
14f6dfc29d fix: Improve Browser Startup and Error Handling
- Add `--no-sandbox` flag to resolve browser startup issues
- Enhance error handling in temp email creation
- Update localization files with new email-related messages
- Improve translation support for email creation process
2025-03-06 11:01:34 +08:00
Pin Studios
2e9bd269ad Update README.md 2025-03-03 15:24:36 +08:00
Pin Studios
f9b7e23253 Update README.md 2025-03-03 15:19:44 +08:00
yeongpin
0d979f7543 chore: Bump default version to 1.5.03 in build workflow 2025-03-03 11:59:15 +08:00
yeongpin
cce3025f7f feat: Enhance Name Generation and Improve Account Registration Process
- Implement realistic name generation with predefined name lists
- Modify first name letter for uniqueness
- Add more descriptive console output with emojis and translations
- Update localization files with new registration-related keys
- Optimize random name generation in registration modules
2025-03-03 11:58:28 +08:00
Pin Studios
fe3e27561b Update .env 2025-03-03 11:17:35 +08:00
yeongpin
bf2bea71eb Merge branch 'main' of https://github.com/yeongpin/cursor-free-vip 2025-03-03 11:16:45 +08:00
yeongpin
77a61647dd docs: Update CHANGELOG with version 1.5.01 release notes 2025-03-03 11:10:10 +08:00
yeongpin
813dd4431e feat: Add version update checker with GitHub release support 2025-03-03 11:09:11 +08:00
Pin Studios
d7116b8cf3 Update .env 2025-03-02 13:55:25 +08:00
Pin Studios
f5a7acc4e3 Merge pull request #122 from bingoohuang/main
print account info as early as possible
2025-03-02 13:54:58 +08:00
bingoohuang
479933844a print account info as early as possible 2025-02-28 21:20:12 +08:00
yeongpin
93046d7f03 Update README.md with improved image styling and new screenshot 2025-02-27 10:44:18 +08:00
Pin Studios
e7ca31b710 Update build.yml 2025-02-27 10:33:53 +08:00
Pin Studios
87b99b0d16 Update CHANGELOG.md 2025-02-27 10:29:10 +08:00
Pin Studios
e983b6f560 Update .env 2025-02-27 10:27:18 +08:00
Pin Studios
21ca7ab24f Merge pull request #111 from ahmed98Osama/feature/return-to-menu
Return to main menu after each operation
2025-02-27 10:27:00 +08:00
Ahmed Osama
e7468644a4 feat: return to main menu after each operation instead of exiting 2025-02-26 19:07:14 +02:00
Pin Studios
2bca7d7d14 Update install.sh 2025-02-26 22:34:38 +08:00
Pin Studios
040c5f5836 Update install.ps1 2025-02-26 22:30:56 +08:00
Pin Studios
4a86bbeeb4 Update block_domain.txt 2025-02-26 22:01:53 +08:00
Pin Studios
68b7888a83 Merge pull request #101 from aliensb/main
add support for linux
2025-02-25 23:56:29 +08:00
yeongpin
78dee025a7 feat: Enhance Temporary Email Service with Domain Blocking and Improved Error Handling
- Add domain blocking mechanism to filter out problematic email domains
- Implement dynamic domain list retrieval from external source
- Improve error handling and logging in email creation process
- Add fallback service switching when domains are blocked
- Update localization files with new error and blocking-related messages
- Increment version to 1.4.06
2025-02-25 23:53:55 +08:00
Pin Studios
17c2b4b243 Create block_domain.txt 2025-02-25 23:30:53 +08:00
tom
2acb271f19 add support for linux 2025-02-25 16:52:32 +08:00
Pin Studios
b688b67c26 Update .gitignore 2025-02-25 12:23:45 +08:00
yeongpin
3543615a69 fix: Improve Windows Language Detection and Platform Compatibility
- Correct Windows language detection method in Translator class
- Update platform system check for Windows-specific imports
- Refactor language detection to use platform-specific checks
- Ensure more robust cross-platform language detection logic
2025-02-25 12:16:55 +08:00
yeongpin
24b0a5c09e refactor: Streamline System Language Detection Logic
- Consolidate language detection methods into a single unified approach
- Improve cross-platform language detection for Windows and Unix-like systems
- Simplify error handling and add more robust language code mapping
- Remove platform-specific detection methods in favor of a more generic approach
- Enhance language fallback mechanism with better default handling
2025-02-25 12:14:54 +08:00
yeongpin
5bbba05f69 feat: Improve System Language Detection in Translator Class
- Refactor language detection method with separate methods for Windows, macOS, and Linux
- Add more robust language detection for different platforms
- Improve error handling and fallback mechanisms
- Ensure consistent language code formatting (zh_CN, zh_TW)
- Update Windows language detection using windll with additional error checks
2025-02-25 12:09:13 +08:00
yeongpin
72c95e4b4f refactor: Simplify OS Detection and Download Process
- Streamline OS detection logic by removing detailed architecture checks
- Reduce complexity in download URL generation
- Remove verbose download verification steps
- Simplify error handling during binary download
2025-02-25 12:00:59 +08:00
yeongpin
8afd5df4ea fix: Correct Syntax Error in Installation Script Conditional Logic
- Fix incorrect brace placement in install_cursor_free_vip function
- Remove unnecessary closing brace that was causing syntax error
- Ensure proper flow control in installation script
2025-02-25 11:55:38 +08:00
yeongpin
a7a97b5621 feat: Enhance OS Detection and Download Resilience in Installation Script
- Add Windows system detection
- Implement fallback mechanism for macOS binary downloads
- Improve download link verification with HEAD request
- Add graceful handling for missing architecture-specific binaries
- Provide more informative error messages during download process
2025-02-25 11:54:45 +08:00
yeongpin
e2e2ebc12e feat: Enhance Download Verification in Installation Script
- Add verbose curl download logging
- Implement file size check for downloaded binaries
- Provide detailed error messages for download failures
- Improve download error handling and diagnostics
2025-02-25 11:53:37 +08:00
yeongpin
d131bccac0 feat: Improve macOS Architecture Detection in Installation Script
- Add detailed macOS architecture detection (ARM64 and Intel)
- Enhance system type logging with informative messages
- Provide more precise OS and architecture identification
2025-02-25 11:50:39 +08:00
yeongpin
d852bcff50 feat: Enhance Multilingual Support and System Language Detection
- Add automatic system language detection for Windows and Unix-like systems
- Update localization files with new translation keys
- Improve language handling in various modules
- Translate more UI messages to English
- Add GitHub link to logo display
- Bump version to 1.4.04
2025-02-25 10:46:36 +08:00
Pin Studios
4c91525082 Merge pull request #94 from UntaDotMy/main
feat: Add support for Cursor v0.46.X and improve email service
2025-02-25 10:35:34 +08:00
BilaUnta
b565232ba6 bump version 2025-02-25 09:26:10 +08:00
BilaUnta
5725a2b2f7 improve for 1.4.03 2025-02-25 09:22:22 +08:00
yeongpin
6ec6f8bdbf Add license section to README.md 2025-02-24 12:11:20 +08:00
yeongpin
5c1bcff55a Update Readme 2025-02-24 11:43:54 +08:00
yeongpin
025c4e2ef3 Update readme 2025-02-24 11:30:34 +08:00
yeongpin
6ac1294bee Add Disable Cursor Auto Update Feature 2025-02-24 11:18:57 +08:00
Pin Studios
fb443592d3 Update README.md 2025-02-21 18:02:22 +08:00
Pin Studios
c30a62b072 Update README.md 2025-02-17 16:30:55 +08:00
Pin Studios
8bc509cccf Update README.md 2025-02-17 16:29:16 +08:00
yeongpin
9f814708d1 Update CHANGELOG.md for v1.3.02 release 2025-02-13 15:33:09 +08:00
Pin Studios
1889f9827a Update README.md 2025-02-13 15:28:00 +08:00
yeongpin
57d2d40e67 update coffee 2025-02-13 15:24:40 +08:00
28 changed files with 1491 additions and 558 deletions

4
.env
View File

@@ -1,2 +1,2 @@
version=1.3.02
VERSION=1.3.02
version=1.6.01
VERSION=1.6.01

View File

@@ -6,7 +6,7 @@ on:
version:
description: 'Version number (e.g. 1.0.9)'
required: true
default: '1.0.9-dev'
default: '1.5.03'
permissions:
contents: write
@@ -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,25 +189,21 @@ 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:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

50
.gitignore vendored Normal file
View File

@@ -0,0 +1,50 @@
__pycache__
server/
venv/
check_license.py
cursor_modifier.py
reset_machine.py
Run_Venv.bat
token_monitor.py
get_mac.py
.gitignore
build.bat
build.mac.command
build.py
build.sh
ENV/
install.bat
run.bat
temp_account_info.txt
.env copy
# PyInstaller
build/
dist/
*.spec2
credentials.txt
cursor_accounts.txt
recaptcha.py
install_requirements.bat
# IDE
.idea/
.vscode/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Project specific
*.log
*.db
*.sqlite3
# Mac
run_venv.mac.command

View File

@@ -1,5 +1,79 @@
# Change Log
## v1.6.01
1. Fix: Cursor Auth | 修復Cursor Auth
2. Add: Create Account Maximum Retry | 增加創建賬號最大重試次數
3. Fix: Cursor Auth Error | 修復Cursor Auth錯誤
4. Fix: Update Curl Faild | 修復更新Curl失敗
## v1.5.03
1. HOTFIX: Stuck on starting browser | 修復啟動瀏覽器卡住問題
2. Small Fix: Error Handling | 小修錯誤處理
3. Small Fix: Translation | 小修翻譯
4. Small Fix: Performance | 小修性能
## v1.5.02
1. Add: Generate Random Name Alias | 增加生成隨機真實姓名
2. Add: Realistic Name Input | 增加真實姓名輸入
3. Optimize: Error Handling | 優化錯誤處理
4. Optimize: Translation | 優化翻譯
5. Optimize: Performance | 優化性能
## v1.5.01
1. Add: Check Latest Version | 增加檢查最新版本
2. Add: Update Command | 增加更新命令
## v1.4.08
1. Add: Print Some Account Info | 增加打印一些賬號信息
## v1.4.07
1. Add Removed break statements after each operation | 修改結束event後的break暫停應用
2. Added print_menu() calls to show the menu again | 添加print_menu調用以再次顯示菜單
3. Updated error handling to show menu instead of exiting | 更新錯誤處理以顯示菜單而不是退出
## v1.4.06
1. Add: Blocked Domains Loaded | 增加被屏蔽的域名加載
2. Fix: Cleanup Error | 修復清理進程時出錯
3. Fix: Blocked Domains Loaded Error | 修復被屏蔽的域名加載錯誤
4. Fix: Available Domains Loaded Error | 修復可用域名加載錯誤
5. Fix: Domains Filtered Error | 修復過濾後剩餘域名錯誤
6. Fix: Domains Excluded Error | 修復排除域名錯誤
## v1.4.05
1. Fix: macOS Language Detection | 修復macOS語言檢測
## v1.4.04
1. Change Some Language Info to English | 更改一些語言信息為英文
2. Add Auto Detect System Language | 增加自動檢測系統語言
3. Fixed Some Issues | 修復一些問題
## 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自動升級
## v1.3.02
1. Add Buy Me a Coffee | 增加請我喝杯咖啡
2. Add PayPal | 增加PayPal
3. Very Small Fix | 非常小的修復
4. Fix main.py option number | 修復main.py選項數量
## v1.3.01
1. Add Manual Email Input | 增加手動輸入郵箱地址
@@ -156,4 +230,4 @@
<p align="center">
<img src="./images/pro_2025-01-11_16-24-03.png" alt="Cursor Pro Logo" width="400"/><br>
</p>
</p>

View File

@@ -1,7 +1,7 @@
# ➤ Cursor Free VIP
<div align="center">
<p align="center">
<img src="./images/logo.png" alt="Cursor Pro Logo" width="200"/>
<img src="./images/logo.png" alt="Cursor Pro Logo" width="200" style="border-radius: 6px;"/>
</p>
<p align="center">
@@ -9,16 +9,17 @@
[![Release](https://img.shields.io/github/v/release/yeongpin/cursor-free-vip?style=flat-square&logo=github&color=blue)](https://github.com/yeongpin/cursor-free-vip/releases/latest)
[![License: CC BY-NC-ND 4.0](https://img.shields.io/badge/License-CC_BY--NC--ND_4.0-lightgrey.svg)](https://creativecommons.org/licenses/by-nc-nd/4.0/)
[![Stars](https://img.shields.io/github/stars/yeongpin/cursor-free-vip?style=flat-square&logo=github)](https://github.com/yeongpin/cursor-free-vip/stargazers)
[![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)
</p>
<h4>Support Latest 0.45.11 Version | 支持最新0.45.11版本</h4>
<h4>Support Latest 0.46.8 Version | 支持最新0.46.8本</h4>
This is a tool to automatically register , support Windows and macOS systems, complete Auth verification, and reset Cursor's configuration.
這是一個自動化工具,自動註冊除了Google驗證碼),支持 Windows 和 macOS 系統完成Auth驗證重置Cursor的配置。
這是一個自動化工具,自動註冊 ,支持 Windows 和 macOS 系統完成Auth驗證重置Cursor的配置。
<p align="center">
<img src="./images/pronew_2025-02-13_15-01-32.png" alt="new" width="400"/><br>
<img src="./images/new_2025-02-27_10-42-44.png" alt="new" width="400" style="border-radius: 6px;"/><br>
</p>
##### If you dont have google chrome , you can download it from [here](https://www.google.com/intl/en_pk/chrome/)
@@ -85,6 +86,8 @@ irm https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/rese
## ❗ Note | 注意事項
* Use administrator to run the script <br>請使用管理員身份運行腳本
* Confirm that Cursor is closed before running the script <br>請確保在運行腳本前已經關閉 Cursor<br>
* This tool is only for learning and research purposes <br>此工具僅供學習和研究使用<br>
@@ -106,11 +109,46 @@ irm https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/rese
歡迎提交 Issue 和 Pull Request
<a href="https://github.com/yeongpin/cursor-free-vip/graphs/contributors">
<img src="https://contrib.rocks/image?repo=yeongpin/cursor-free-vip" />
</a>
<br /><br />
## 📩 Disclaimer | 免責聲明
本工具僅供學習和研究使用,使用本工具所產生的任何後果由使用者自行承擔。 <br>
源代碼靈感來之 | Original code inspiration from [Here](https://github.com/hmhm2022/gpt-cursor-auto)
This tool is only for learning and research purposes, and any consequences arising from the use of this tool are borne by the user.
## 💰 Buy Me a Coffee | 請我喝杯咖啡
<div align="center">
<table>
<tr>
<td>
<img src="./images/provi-code.jpg" alt="buy_me_a_coffee" width="280"/><br>
</td>
<td>
<img src="./images/paypal.png" alt="buy_me_a_coffee" width="280"/><br>
</td>
</tr>
</table>
</div>
## ⭐ Star History | 星星數
<div align="center">
[![Star History Chart](https://api.star-history.com/svg?repos=yeongpin/cursor-free-vip&type=Date)](https://star-history.com/#yeongpin/cursor-free-vip&Date)
</div>
## 📝 License | 授權
本項目採用 [CC BY-NC-ND 4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/) 授權。
Please refer to the [LICENSE](LICENSE.md) file for details.

3
block_domain.txt Normal file
View File

@@ -0,0 +1,3 @@
oakon.com
famamail.com
2925.com

View File

@@ -2,28 +2,28 @@
chcp 65001 > nul
cls
:: 檢查是否以管理員權限運行
:: Check if running with administrator privileges
net session >nul 2>&1
if %errorLevel% == 0 (
:: 如果是管理員權限,只創建虛擬環境後就降權運行
:: If running with administrator privileges, create virtual environment and then run with normal user privileges
if not exist venv (
echo 正在創建虛擬環境...
python -m venv venv
)
:: 降權運行剩餘的步驟
:: Run remaining steps with normal user privileges
echo 以普通用戶權限繼續...
powershell -Command "Start-Process -FilePath '%comspec%' -ArgumentList '/c cd /d %cd% && %~f0 run' -Verb RunAs:NO"
exit /b
) else (
:: 檢查是否是第二階段運行
:: Check if running in second stage
if "%1"=="run" (
goto RUN_BUILD
) else (
:: 如果是普通權限且需要創建虛擬環境,請求管理員權限
:: If running with normal privileges and creating virtual environment is required, request administrator privileges
if not exist venv (
echo ⚠️ 需要管理員權限來創建虛擬環境
echo 正在請求管理員權限...
echo ⚠️ Requires administrator privileges to create virtual environment
echo Requesting administrator privileges...
powershell -Command "Start-Process -Verb RunAs -FilePath '%comspec%' -ArgumentList '/c cd /d %cd% && %~f0'"
exit /b
) else (
@@ -33,30 +33,30 @@ if %errorLevel% == 0 (
)
:RUN_BUILD
echo 啟動虛擬環境...
echo Starting virtual environment...
call venv\Scripts\activate.bat
if errorlevel 1 (
echo啟動虛擬環境失敗
echoFailed to start virtual environment
pause
exit /b 1
)
:: 檢查並安裝缺失的依賴
echo 檢查依賴...
:: Check and install missing dependencies
echo Checking dependencies...
for /f "tokens=1" %%i in (requirements.txt) do (
pip show %%i >nul 2>&1 || (
echo 安裝 %%i...
echo Installing %%i...
pip install %%i
)
)
echo 開始構建...
echo Starting build...
python build.py
if errorlevel 1 (
echo構建失敗
echoBuild failed
pause
exit /b 1
)
echo完成!
echoCompleted!
pause

View File

@@ -8,7 +8,7 @@ import shutil
from logo import print_logo
from dotenv import load_dotenv
# 忽略特定警告
# Ignore specific warnings
warnings.filterwarnings("ignore", category=SyntaxWarning)
class LoadingAnimation:
@@ -50,21 +50,21 @@ def simulate_progress(message, duration=1.0, steps=20):
progress_bar(i, steps, prefix="Progress:", length=40)
def build():
# 清理屏幕
# Clean screen
os.system("cls" if platform.system().lower() == "windows" else "clear")
# 顯示 logo
# Display logo
print_logo()
# 清理 PyInstaller 緩存
print("\033[93m🧹 清理構建緩存...\033[0m")
# Clean PyInstaller cache
print("\033[93m🧹 Cleaning build cache...\033[0m")
if os.path.exists('build'):
shutil.rmtree('build')
# 重新加載環境變量以確保獲取最新版本
# Reload environment variables to ensure getting the latest version
load_dotenv(override=True)
version = os.getenv('VERSION', '1.0.0')
print(f"\033[93m📦 正在構建版本: v{version}\033[0m")
print(f"\033[93m📦 Building version: v{version}\033[0m")
try:
simulate_progress("Preparing build environment...", 0.5)
@@ -72,7 +72,7 @@ def build():
loading = LoadingAnimation()
loading.start("Building in progress")
# 根据系统类型设置输出名称
# Set output name based on system type
system = platform.system().lower()
if system == "windows":
os_type = "windows"
@@ -86,7 +86,7 @@ def build():
output_name = f"CursorFreeVIP_{version}_{os_type}"
# 构建命令
# Build command
build_command = f'pyinstaller --clean --noconfirm build.spec'
output_path = os.path.join('dist', f'{output_name}{ext}')
@@ -95,16 +95,16 @@ def build():
loading.stop()
if os.path.exists(output_path):
print(f"\n\033[92m✅ 構建完成!")
print(f"📦 可執行文件位於: {output_path}\033[0m")
print(f"\n\033[92m✅ Build completed!")
print(f"📦 Executable file located: {output_path}\033[0m")
else:
print("\n\033[91m❌ 構建失敗:未找到輸出文件\033[0m")
print("\n\033[91m❌ Build failed: Output file not found\033[0m")
return False
except Exception as e:
if loading:
loading.stop()
print(f"\n\033[91m❌ 構建過程出錯: {str(e)}\033[0m")
print(f"\n\033[91m❌ Build process error: {str(e)}\033[0m")
return False
return True

View File

@@ -8,7 +8,7 @@ NC='\033[0m' # No Color
# 检查并安装必要的依赖
check_dependencies() {
echo -e "${YELLOW}检查系统依赖...${NC}"
echo -e "${YELLOW}Checking system dependencies...${NC}"
# 检查是否为 Ubuntu/Debian
if [ -f /etc/debian_version ]; then
@@ -16,42 +16,42 @@ check_dependencies() {
PACKAGES="python3 python3-pip python3-venv"
for pkg in $PACKAGES; do
if ! dpkg -l | grep -q "^ii $pkg "; then
echo -e "${YELLOW}安装 $pkg...${NC}"
echo -e "${YELLOW}Installing $pkg...${NC}"
sudo apt-get update
sudo apt-get install -y $pkg
fi
done
else
echo -e "${RED}不支持的系统,请手动安装 python3, pip3 python3-venv${NC}"
echo -e "${RED}Unsupported system, please install python3, pip3 and python3-venv manually${NC}"
exit 1
fi
}
# 创建并激活虚拟环境
setup_venv() {
echo -e "${GREEN}正在创建虚拟环境...${NC}"
echo -e "${GREEN}Creating virtual environment...${NC}"
python3 -m venv venv
echo -e "${GREEN}启动虚拟环境...${NC}"
echo -e "${GREEN}Starting virtual environment...${NC}"
. ./venv/bin/activate || source ./venv/bin/activate
}
# 安装依赖
install_dependencies() {
echo -e "${GREEN}安装依赖...${NC}"
echo -e "${GREEN}Installing dependencies...${NC}"
python3 -m pip install --upgrade pip
pip3 install -r requirements.txt
}
# 构建程序
build_program() {
echo -e "${GREEN}开始构建...${NC}"
echo -e "${GREEN}Starting build...${NC}"
python3 build.py
}
# 清理
cleanup() {
echo -e "${GREEN}清理虚拟环境...${NC}"
echo -e "${GREEN}Cleaning virtual environment...${NC}"
deactivate 2>/dev/null || true
rm -rf venv
}
@@ -73,8 +73,8 @@ main() {
# 清理
cleanup
echo -e "${GREEN}完成!${NC}"
echo "按任意键退出..."
echo -e "${GREEN}Completed!${NC}"
echo "Press any key to exit..."
# 使用兼容的方式读取输入
if [ "$(uname)" = "Linux" ]; then
read dummy

View File

@@ -45,65 +45,6 @@ class BrowserControl:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.create_new_tab_failed', error=str(e))}{Style.RESET_ALL}")
return None
def switch_to_tab(self, browser):
"""切换到指定浏览器窗口"""
try:
self.browser = browser
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.switch_tab_success')}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.switch_tab_failed', error=str(e))}{Style.RESET_ALL}")
return False
def get_current_tab(self):
"""获取当前标签页"""
return self.browser
def wait_for_page_load(self, seconds=2):
"""等待页面加载"""
time.sleep(seconds)
def navigate_to(self, url):
"""导航到指定URL"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('control.navigate_to', url=url)}...{Style.RESET_ALL}")
self.browser.get(url)
self.wait_for_page_load()
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.browser_error', error=str(e))}{Style.RESET_ALL}")
return False
def get_verification_code(self):
"""从邮件中获取验证码"""
try:
# 尝试所有可能的样式组合
selectors = [
# 新样式
'xpath://div[contains(@style, "font-family:-apple-system") and contains(@style, "font-size:28px") and contains(@style, "letter-spacing:2px") and contains(@style, "color:#202020")]',
# 带行高的样式
'xpath://div[contains(@style, "font-size:28px") and contains(@style, "letter-spacing:2px") and contains(@style, "line-height:30px")]',
# rgba 颜色样式
'xpath://div[contains(@style, "font-size: 28px") and contains(@style, "letter-spacing: 2px") and contains(@style, "color: rgba(32, 32, 32, 1)")]',
# 宽松样式
'xpath://div[contains(@style, "font-size:28px") and contains(@style, "letter-spacing:2px")]'
]
# 依次尝试每个选择器
for selector in selectors:
code_div = self.browser.ele(selector)
if code_div:
verification_code = code_div.text.strip()
if verification_code.isdigit() and len(verification_code) == 6:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.found_verification_code')}: {verification_code}{Style.RESET_ALL}")
return verification_code
print(f"{Fore.YELLOW}{EMOJI['ERROR']} {self.translator.get('control.no_valid_verification_code')}{Style.RESET_ALL}")
return None
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_verification_code_error', error=str(e))}{Style.RESET_ALL}")
return None
def fill_verification_code(self, code):
"""填写验证码"""

View File

@@ -22,14 +22,38 @@ class CursorAuth:
def __init__(self, translator=None):
self.translator = translator
# 判断操作系统
if os.name == "nt": # Windows
if sys.platform == "win32": # Windows
self.db_path = os.path.join(
os.getenv("APPDATA"), "Cursor", "User", "globalStorage", "state.vscdb"
)
else: # macOS
elif sys.platform == 'linux':
self.db_path = os.path.expanduser(
"~/.config/Cursor/User/globalStorage/state.vscdb"
)
elif sys.platform == 'darwin': # macOS
self.db_path = os.path.expanduser(
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
)
else:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.unsupported_platform')}{Style.RESET_ALL}")
sys.exit(1)
# 检查数据库文件是否存在
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
@@ -66,13 +90,16 @@ class CursorAuth:
# 设置要更新的键值对
updates = []
updates.append(("cursorAuth/cachedSignUpType", "Auth_0"))
if email is not None:
updates.append(("cursorAuth/cachedEmail", email))
if access_token is not None:
updates.append(("cursorAuth/accessToken", access_token))
if refresh_token is not None:
updates.append(("cursorAuth/refreshToken", refresh_token))
updates.append(("cursorAuth/cachedSignUpType", "Auth_0"))
# 使用事务来确保数据完整性
cursor.execute("BEGIN TRANSACTION")
@@ -110,5 +137,3 @@ class CursorAuth:
if conn:
conn.close()
print(f"{EMOJI['DB']} {Fore.CYAN} {self.translator.get('auth.database_connection_closed')}{Style.RESET_ALL}")

View File

@@ -10,10 +10,10 @@ from reset_machine_manual import MachineIDResetter
os.environ["PYTHONVERBOSE"] = "0"
os.environ["PYINSTALLER_VERBOSE"] = "0"
# 初始化colorama
# Initialize colorama
init()
# 定义emoji常量
# Define emoji constants
EMOJI = {
'START': '🚀',
'FORM': '📝',
@@ -33,7 +33,7 @@ EMOJI = {
class CursorRegistration:
def __init__(self, translator=None):
self.translator = translator
# 设置为显示模式
# Set to display mode
os.environ['BROWSER_HEADLESS'] = 'False'
self.browser_manager = BrowserManager()
self.browser = None
@@ -47,39 +47,49 @@ class CursorRegistration:
# 账号信息
self.password = self._generate_password()
self.first_name = self._generate_name()
self.last_name = self._generate_name()
# Generate first name and last name separately
first_name = random.choice([
"James", "John", "Robert", "Michael", "William", "David", "Joseph", "Thomas",
"Emma", "Olivia", "Ava", "Isabella", "Sophia", "Mia", "Charlotte", "Amelia",
"Liam", "Noah", "Oliver", "Elijah", "Lucas", "Mason", "Logan", "Alexander"
])
self.last_name = random.choice([
"Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis",
"Anderson", "Wilson", "Taylor", "Thomas", "Moore", "Martin", "Jackson", "Lee",
"Thompson", "White", "Harris", "Clark", "Lewis", "Walker", "Hall", "Young"
])
# Modify first letter of first name
new_first_letter = random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
self.first_name = new_first_letter + first_name[1:]
print(f"\n{Fore.CYAN}{EMOJI['PASSWORD']} {self.translator.get('register.password')}: {self.password} {Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['FORM']} {self.translator.get('register.first_name')}: {self.first_name} {Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['FORM']} {self.translator.get('register.last_name')}: {self.last_name} {Style.RESET_ALL}")
def _generate_password(self, length=12):
"""Generate Random Password"""
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
return ''.join(random.choices(chars, k=length))
def _generate_name(self, length=6):
"""Generate Random Name"""
first_letter = random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
rest_letters = ''.join(random.choices("abcdefghijklmnopqrstuvwxyz", k=length-1))
return first_letter + rest_letters
def setup_email(self):
"""设置邮箱"""
"""Setup Email"""
try:
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.browser_start')}...{Style.RESET_ALL}")
# 使用 new_tempemail 创建临时邮箱,传入 translator
# Create a temporary email using new_tempemail, passing translator
from new_tempemail import NewTempEmail
self.temp_email = NewTempEmail(self.translator) # 传入 translator
self.temp_email = NewTempEmail(self.translator) # Pass translator
# 创建临时邮箱
# Create a temporary email
email_address = self.temp_email.create_email()
if not email_address:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.email_create_failed')}{Style.RESET_ALL}")
return False
# 保存邮箱地址和浏览器实例
# Save email address
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 # Pass NewTempEmail instance
return True
@@ -93,10 +103,10 @@ class CursorRegistration:
try:
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.register_start')}...{Style.RESET_ALL}")
# 直接使用 new_signup.py 进行注册
# Directly use new_signup.py to sign up
from new_signup import main as new_signup_main
# 执行新的注册流程,传入 translator
# Execute the new registration process, passing translator
result, browser_tab = new_signup_main(
email=self.email_address,
password=self.password,
@@ -108,11 +118,11 @@ class CursorRegistration:
)
if result:
# 使用返回的浏览器实例获取账户信息
self.signup_tab = browser_tab # 保存浏览器实例
# Use the returned browser instance to get account information
self.signup_tab = browser_tab # Save browser instance
success = self._get_account_info()
# 获取信息后关闭浏览器
# Close browser after getting information
if browser_tab:
try:
browser_tab.quit()
@@ -127,7 +137,7 @@ class CursorRegistration:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.register_process_error', error=str(e))}{Style.RESET_ALL}")
return False
finally:
# 确保在任何情况下都关闭浏览器
# Ensure browser is closed in any case
if browser_tab:
try:
browser_tab.quit()
@@ -135,7 +145,7 @@ class CursorRegistration:
pass
def _get_account_info(self):
"""获取账户信息和 Token"""
"""Get Account Information and Token"""
try:
self.signup_tab.get(self.settings_url)
time.sleep(2)
@@ -150,6 +160,7 @@ class CursorRegistration:
if usage_ele:
total_usage = usage_ele.text.split("/")[-1].strip()
print(f"Total Usage: {total_usage}\n")
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
max_attempts = 30
retry_interval = 2
@@ -186,7 +197,7 @@ class CursorRegistration:
return False
def _save_account_info(self, token, total_usage):
"""保存账户信息到文件"""
"""Save Account Information to File"""
try:
# 先更新认证信息
print(f"{Fore.CYAN}{EMOJI['KEY']} {self.translator.get('register.update_cursor_auth_info')}...{Style.RESET_ALL}")
@@ -201,7 +212,7 @@ class CursorRegistration:
if not resetter.reset_machine_ids(): # 直接调用reset_machine_ids方法
raise Exception("Failed to reset machine ID")
# 保存账户信息到文件
# Save account information to file
with open('cursor_accounts.txt', 'a', encoding='utf-8') as f:
f.write(f"\n{'='*50}\n")
f.write(f"Email: {self.email_address}\n")
@@ -218,7 +229,7 @@ class CursorRegistration:
return False
def start(self):
"""启动注册流程"""
"""Start Registration Process"""
try:
if self.setup_email():
if self.register_cursor():
@@ -226,7 +237,7 @@ class CursorRegistration:
return True
return False
finally:
# 关闭邮箱标签页
# Close email tab
if hasattr(self, 'temp_email'):
try:
self.temp_email.close()
@@ -234,7 +245,7 @@ class CursorRegistration:
pass
def update_cursor_auth(self, email=None, access_token=None, refresh_token=None):
"""更新Cursor的认证信息的便捷函数"""
"""Update Cursor Auth Info"""
auth_manager = CursorAuth(translator=self.translator)
return auth_manager.update_auth(email, access_token, refresh_token)

View File

@@ -10,10 +10,10 @@ from reset_machine_manual import MachineIDResetter
os.environ["PYTHONVERBOSE"] = "0"
os.environ["PYINSTALLER_VERBOSE"] = "0"
# 初始化colorama
# Initialize colorama
init()
# 定义emoji常量
# Define emoji constants
EMOJI = {
'START': '🚀',
'FORM': '📝',
@@ -33,7 +33,7 @@ EMOJI = {
class CursorRegistration:
def __init__(self, translator=None):
self.translator = translator
# 设置为显示模式
# Set to display mode
os.environ['BROWSER_HEADLESS'] = 'False'
self.browser_manager = BrowserManager()
self.browser = None
@@ -44,32 +44,44 @@ class CursorRegistration:
self.signup_tab = None
self.email_tab = None
# 账号信息
# Generate account information
self.password = self._generate_password()
self.first_name = self._generate_name()
self.last_name = self._generate_name()
# Generate first name and last name separately
first_name = random.choice([
"James", "John", "Robert", "Michael", "William", "David", "Joseph", "Thomas",
"Emma", "Olivia", "Ava", "Isabella", "Sophia", "Mia", "Charlotte", "Amelia",
"Liam", "Noah", "Oliver", "Elijah", "Lucas", "Mason", "Logan", "Alexander"
])
self.last_name = random.choice([
"Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis",
"Anderson", "Wilson", "Taylor", "Thomas", "Moore", "Martin", "Jackson", "Lee",
"Thompson", "White", "Harris", "Clark", "Lewis", "Walker", "Hall", "Young"
])
# Modify first letter of first name
new_first_letter = random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
self.first_name = new_first_letter + first_name[1:]
print(f"\n{Fore.CYAN}{EMOJI['PASSWORD']} {self.translator.get('register.password')}: {self.password} {Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['FORM']} {self.translator.get('register.first_name')}: {self.first_name} {Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['FORM']} {self.translator.get('register.last_name')}: {self.last_name} {Style.RESET_ALL}")
def _generate_password(self, length=12):
"""Generate Random Password"""
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
return ''.join(random.choices(chars, k=length))
def _generate_name(self, length=6):
"""Generate Random Name"""
first_letter = random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
rest_letters = ''.join(random.choices("abcdefghijklmnopqrstuvwxyz", k=length-1))
return first_letter + rest_letters
def setup_email(self):
"""设置邮箱"""
"""Setup Email"""
try:
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.manual_email_input') if self.translator else '请输入邮箱地址:'}")
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.manual_email_input') if self.translator else 'Please enter your email address:'}")
self.email_address = input().strip()
if '@' not in self.email_address:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_email') if self.translator else '无效的邮箱地址'}{Style.RESET_ALL}")
return False
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('register.email_address')}: {self.email_address}\n{Style.RESET_ALL}")
return True
except Exception as e:
@@ -77,9 +89,9 @@ class CursorRegistration:
return False
def get_verification_code(self):
"""手动获取验证码"""
"""Manually Get Verification Code"""
try:
print(f"{Fore.CYAN}{EMOJI['CODE']} {self.translator.get('register.manual_code_input') if self.translator else '请输入验证码:'}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['CODE']} {self.translator.get('register.manual_code_input') if self.translator else 'Please enter the verification code:'}")
code = input().strip()
if not code.isdigit() or len(code) != 6:
@@ -93,31 +105,31 @@ class CursorRegistration:
return None
def register_cursor(self):
"""注册 Cursor"""
"""Register Cursor"""
browser_tab = None
try:
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.register_start')}...{Style.RESET_ALL}")
# 直接使用 new_signup.py 进行注册
# Use new_signup.py directly for registration
from new_signup import main as new_signup_main
# 执行新的注册流程,传入 translator
# Execute new registration process, passing translator
result, browser_tab = new_signup_main(
email=self.email_address,
password=self.password,
first_name=self.first_name,
last_name=self.last_name,
email_tab=None, # 不需要邮箱标签页
controller=self, # 传入 self 而不是 self.controller
email_tab=None, # No email tab needed
controller=self, # Pass self instead of self.controller
translator=self.translator
)
if result:
# 使用返回的浏览器实例获取账户信息
self.signup_tab = browser_tab # 保存浏览器实例
# Use the returned browser instance to get account information
self.signup_tab = browser_tab # Save browser instance
success = self._get_account_info()
# 获取信息后关闭浏览器
# Close browser after getting information
if browser_tab:
try:
browser_tab.quit()
@@ -132,7 +144,7 @@ class CursorRegistration:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.register_process_error', error=str(e))}{Style.RESET_ALL}")
return False
finally:
# 确保在任何情况下都关闭浏览器
# Ensure browser is closed in any case
if browser_tab:
try:
browser_tab.quit()
@@ -140,7 +152,7 @@ class CursorRegistration:
pass
def _get_account_info(self):
"""获取账户信息和 Token"""
"""Get Account Information and Token"""
try:
self.signup_tab.get(self.settings_url)
time.sleep(2)
@@ -155,6 +167,7 @@ class CursorRegistration:
if usage_ele:
total_usage = usage_ele.text.split("/")[-1].strip()
print(f"Total Usage: {total_usage}\n")
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
max_attempts = 30
retry_interval = 2
@@ -191,22 +204,22 @@ class CursorRegistration:
return False
def _save_account_info(self, token, total_usage):
"""保存账户信息到文件"""
"""Save Account Information to File"""
try:
# 先更新认证信息
# Update authentication information first
print(f"{Fore.CYAN}{EMOJI['KEY']} {self.translator.get('register.update_cursor_auth_info')}...{Style.RESET_ALL}")
if self.update_cursor_auth(email=self.email_address, access_token=token, refresh_token=token):
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.cursor_auth_info_updated')}...{Style.RESET_ALL}")
else:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.cursor_auth_info_update_failed')}...{Style.RESET_ALL}")
# 重置机器ID
# Reset machine ID
print(f"{Fore.CYAN}{EMOJI['UPDATE']} {self.translator.get('register.reset_machine_id')}...{Style.RESET_ALL}")
resetter = MachineIDResetter(self.translator) # 创建实例时传入translator
if not resetter.reset_machine_ids(): # 直接调用reset_machine_ids方法
resetter = MachineIDResetter(self.translator) # Create instance with translator
if not resetter.reset_machine_ids(): # Call reset_machine_ids method directly
raise Exception("Failed to reset machine ID")
# 保存账户信息到文件
# Save account information to file
with open('cursor_accounts.txt', 'a', encoding='utf-8') as f:
f.write(f"\n{'='*50}\n")
f.write(f"Email: {self.email_address}\n")
@@ -223,7 +236,7 @@ class CursorRegistration:
return False
def start(self):
"""启动注册流程"""
"""Start Registration Process"""
try:
if self.setup_email():
if self.register_cursor():
@@ -231,7 +244,7 @@ class CursorRegistration:
return True
return False
finally:
# 关闭邮箱标签页
# Close email tab
if hasattr(self, 'temp_email'):
try:
self.temp_email.close()
@@ -239,7 +252,7 @@ class CursorRegistration:
pass
def update_cursor_auth(self, email=None, access_token=None, refresh_token=None):
"""更新Cursor的认证信息的便捷函数"""
"""Convenient function to update Cursor authentication information"""
auth_manager = CursorAuth(translator=self.translator)
return auth_manager.update_auth(email, access_token, refresh_token)

135
disable_auto_update.py Normal file
View File

@@ -0,0 +1,135 @@
import os
import sys
import platform
import shutil
from colorama import Fore, Style, init
import subprocess
# Initialize colorama
init()
# Define emoji constants
EMOJI = {
"PROCESS": "🔄",
"SUCCESS": "",
"ERROR": "",
"INFO": "",
"FOLDER": "📁",
"FILE": "📄",
"STOP": "🛑",
"CHECK": "✔️"
}
class AutoUpdateDisabler:
def __init__(self, translator=None):
self.translator = translator
self.system = platform.system()
self.updater_paths = {
"Windows": os.path.join(os.getenv("LOCALAPPDATA", ""), "cursor-updater"),
"Darwin": os.path.expanduser("~/Library/Application Support/cursor-updater"),
"Linux": os.path.expanduser("~/.config/cursor-updater")
}
def _kill_cursor_processes(self):
"""End all Cursor processes"""
try:
print(f"{Fore.CYAN}{EMOJI['PROCESS']} {self.translator.get('update.killing_processes') if self.translator else '正在结束 Cursor 进程...'}{Style.RESET_ALL}")
if self.system == "Windows":
subprocess.run(['taskkill', '/F', '/IM', 'Cursor.exe', '/T'], capture_output=True)
else:
subprocess.run(['pkill', '-f', 'Cursor'], capture_output=True)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.processes_killed') if self.translator else 'Cursor 进程已结束'}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('update.kill_process_failed', error=str(e)) if self.translator else f'结束进程失败: {e}'}{Style.RESET_ALL}")
return False
def _remove_updater_directory(self):
"""Delete updater directory"""
try:
updater_path = self.updater_paths.get(self.system)
if not updater_path:
raise OSError(self.translator.get('update.unsupported_os', system=self.system) if self.translator else f"不支持的操作系统: {self.system}")
print(f"{Fore.CYAN}{EMOJI['FOLDER']} {self.translator.get('update.removing_directory') if self.translator else '正在删除更新程序目录...'}{Style.RESET_ALL}")
if os.path.exists(updater_path):
if os.path.isdir(updater_path):
shutil.rmtree(updater_path)
else:
os.remove(updater_path)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.directory_removed') if self.translator else '更新程序目录已删除'}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('update.remove_directory_failed', error=str(e)) if self.translator else f'删除目录失败: {e}'}{Style.RESET_ALL}")
return False
def _create_blocking_file(self):
"""Create blocking file"""
try:
updater_path = self.updater_paths.get(self.system)
if not updater_path:
raise OSError(self.translator.get('update.unsupported_os', system=self.system) if self.translator else f"不支持的操作系统: {self.system}")
print(f"{Fore.CYAN}{EMOJI['FILE']} {self.translator.get('update.creating_block_file') if self.translator else '正在创建阻止文件...'}{Style.RESET_ALL}")
# Create empty file
open(updater_path, 'w').close()
# Set read-only attribute
if self.system == "Windows":
os.system(f'attrib +r "{updater_path}"')
else:
os.chmod(updater_path, 0o444) # Set to read-only
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.block_file_created') if self.translator else '阻止文件已创建'}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('update.create_block_file_failed', error=str(e)) if self.translator else f'创建阻止文件失败: {e}'}{Style.RESET_ALL}")
return False
def disable_auto_update(self):
"""Disable auto update"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('update.start_disable') if self.translator else '开始禁用自动更新...'}{Style.RESET_ALL}")
# 1. End processes
if not self._kill_cursor_processes():
return False
# 2. Delete directory
if not self._remove_updater_directory():
return False
# 3. Create blocking file
if not self._create_blocking_file():
return False
print(f"{Fore.GREEN}{EMOJI['CHECK']} {self.translator.get('update.disable_success') if self.translator else '自动更新已禁用'}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('update.disable_failed', error=str(e)) if self.translator else f'禁用自动更新失败: {e}'}{Style.RESET_ALL}")
return False
def run(translator=None):
"""Convenient function for directly calling the disable function"""
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['STOP']} {translator.get('update.title') if translator else 'Disable Cursor Auto Update'}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
disabler = AutoUpdateDisabler(translator)
disabler.disable_auto_update()
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
input(f"{EMOJI['INFO']} {translator.get('update.press_enter') if translator else 'Press Enter to Continue...'}")
if __name__ == "__main__":
from main import translator as main_translator
run(main_translator)

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

BIN
images/paypal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
images/provi-code.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

View File

@@ -2,16 +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}",
"press_enter": "Press Enter to Exit"
"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"
},
"languages": {
"en": "English",
@@ -63,25 +64,29 @@
"patch_completed": "Patching getMachineId Completed",
"patch_failed": "Patching getMachineId Failed: {error}",
"version_check_passed": "Cursor Version Check Passed",
"file_modified": "File Modified"
"file_modified": "File Modified",
"version_less_than_0_45": "Cursor Version < 0.45.0, Skip Patching getMachineId",
"detecting_version": "Detecting Cursor Version",
"patching_getmachineid": "Patching getMachineId",
"version_greater_than_0_45": "Cursor Version >= 0.45.0, Patching getMachineId"
},
"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",
@@ -126,7 +131,12 @@
"register_process_error": "Register Process Error: {error}",
"setting_password": "Setting Password",
"manual_code_input": "Manual Code Input",
"manual_email_input": "Manual Email Input"
"manual_email_input": "Manual Email Input",
"password": "Password",
"first_name": "First Name",
"last_name": "Last Name",
"exit_signal": "Exit Signal",
"email_address": "Email Address"
},
"auth": {
"title": "Cursor Auth Manager",
@@ -144,7 +154,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",
@@ -181,7 +194,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}",
@@ -195,6 +208,44 @@
"verification_code_found": "Verification Code Found",
"verification_code_not_found": "Verification Code Not Found",
"verification_code_error": "Verification Code Error: {error}",
"address": "Email Address"
"address": "Email Address",
"all_domains_blocked": "All Domains Blocked, Switching Service",
"no_available_domains_after_filtering": "No Available Domains After Filtering",
"switching_service": "Switching to {service} Service",
"domains_list_error": "Failed to Get Domains List: {error}",
"failed_to_get_available_domains": "Failed to Get Available Domains",
"domains_excluded": "Domains Excluded: {domains}",
"failed_to_create_account": "Failed to Create Account",
"account_creation_error": "Account Creation Error: {error}",
"blocked_domains": "Blocked Domains: {domains}",
"blocked_domains_loaded": "Blocked Domains Loaded: {count}",
"blocked_domains_loaded_error": "Blocked Domains Loaded Error: {error}",
"blocked_domains_loaded_success": "Blocked Domains Loaded Successfully",
"blocked_domains_loaded_timeout": "Blocked Domains Loaded Timeout: {timeout}s",
"blocked_domains_loaded_timeout_error": "Blocked Domains Loaded Timeout Error: {error}",
"available_domains_loaded": "Available Domains Loaded: {count}",
"domains_filtered": "Domains Filtered: {count}",
"trying_to_create_email": "Trying to create email: {email}"
},
"update": {
"title": "Disable Cursor Auto Update",
"disable_success": "Auto Update Disabled Successfully",
"disable_failed": "Disable Auto Update Failed: {error}",
"press_enter": "Press Enter to Exit",
"start_disable": "Start Disabling Auto Update",
"killing_processes": "Killing Processes",
"processes_killed": "Processes Killed",
"removing_directory": "Removing Directory",
"directory_removed": "Directory Removed",
"creating_block_file": "Creating Block File",
"block_file_created": "Block File Created"
},
"updater": {
"checking": "Checking for updates...",
"new_version_available": "New version available! (Current: {current}, Latest: {latest})",
"updating": "Updating to the latest version. The program will restart automatically.",
"up_to_date": "You are using the latest version.",
"check_failed": "Failed to check for updates: {error}",
"continue_anyway": "Continuing with current version..."
}
}

View File

@@ -3,15 +3,16 @@
"title": "可用选项",
"exit": "退出程序",
"reset": "重置机器标识",
"register": "注册 Cursor",
"register_manual": "手动指定邮箱注册 Cursor",
"quit": "退出 Cursor",
"select_language": "选择语言",
"input_choice": "输入选择 ({choices})",
"invalid_choice": "无效选择,请重试",
"program_terminated": "程序被用户终止",
"error_occurred": "发生错误: {error}",
"press_enter": "按回车键退出"
"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",
@@ -63,29 +64,33 @@
"patch_completed": "getMachineId修补完成",
"patch_failed": "getMachineId修补失败: {error}",
"version_check_passed": "Cursor版本检查通过",
"file_modified": "文件已修改"
"file_modified": "文件已修改",
"version_less_than_0_45": "Cursor版本 < 0.45.0跳过getMachineId修补",
"detecting_version": "检测Cursor版本",
"patching_getmachineid": "修补getMachineId",
"version_greater_than_0_45": "Cursor版本 >= 0.45.0修补getMachineId"
},
"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 验证",
@@ -126,7 +131,12 @@
"update_cursor_auth_info": "更新Cursor认证信息",
"setting_password": "设置密码",
"manual_code_input": "手动输入验证码",
"manual_email_input": "手动输入邮箱"
"manual_email_input": "手动输入邮箱",
"password": "密码",
"first_name": "名字",
"last_name": "姓氏",
"exit_signal": "退出信号",
"email_address": "邮箱地址"
},
"auth": {
"title": "Cursor 认证管理器",
@@ -143,7 +153,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": "生成新邮箱",
@@ -178,7 +191,7 @@
},
"email": {
"starting_browser": "启动浏览器",
"visiting_site": "访问 smailpro.com",
"visiting_site": "访问 mail.tm",
"create_success": "邮箱创建成功",
"create_failed": "邮箱创建失败",
"create_error": "邮箱创建错误: {error}",
@@ -192,6 +205,44 @@
"verification_code_found": "找到验证码",
"verification_code_not_found": "未找到验证码",
"verification_code_error": "验证码错误: {error}",
"address": "邮箱地址"
"address": "邮箱地址",
"all_domains_blocked": "所有域名都被屏蔽了,切换服务",
"no_available_domains_after_filtering": "过滤后没有可用域名",
"switching_service": "切换到 {service} 服务",
"domains_list_error": "获取域名列表失败: {error}",
"failed_to_get_available_domains": "获取可用域名失败",
"blocked_domains_loaded": "加载了 {count} 个被屏蔽的域名",
"domains_excluded": "排除了 {domains} 个被屏蔽的域名",
"failed_to_create_account": "创建账户失败",
"account_creation_error": "账户创建错误: {error}",
"blocked_domains": "被屏蔽的域名: {domains}",
"blocked_domains_loaded_error": "加载被屏蔽的域名失败: {error}",
"blocked_domains_loaded_success": "加载被屏蔽的域名成功",
"blocked_domains_loaded_timeout": "加载被屏蔽的域名超时: {timeout}秒",
"blocked_domains_loaded_timeout_error": "加载被屏蔽的域名超时错误: {error}",
"available_domains_loaded": "获取到 {count} 个可用域名",
"domains_filtered": "过滤后剩餘 {count} 個可用域名",
"trying_to_create_email": "尝试创建邮箱: {email}"
},
"update": {
"title": "禁用 Cursor 自动更新",
"disable_success": "自动更新禁用成功",
"disable_failed": "禁用自动更新失败: {error}",
"press_enter": "按回车键退出",
"start_disable": "开始禁用自动更新",
"killing_processes": "杀死进程",
"processes_killed": "进程已杀死",
"removing_directory": "删除目录",
"directory_removed": "目录已删除",
"creating_block_file": "创建阻止文件",
"block_file_created": "阻止文件已创建"
},
"updater": {
"checking": "检查更新...",
"new_version_available": "有新版本可用! (当前版本: {current}, 最新版本: {latest})",
"updating": "正在更新到最新版本。程序将自动重启。",
"up_to_date": "您使用的是最新版本。",
"check_failed": "检查更新失败: {error}",
"continue_anyway": "继续使用当前版本..."
}
}

View File

@@ -1,17 +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": "按回鍵退出"
"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",
@@ -63,53 +64,38 @@
"patch_completed": "getMachineId修補完成",
"patch_failed": "getMachineId修補失敗: {error}",
"version_check_passed": "Cursor版本檢查通過",
"file_modified": "文件已修改"
"file_modified": "文件已修改",
"version_less_than_0_45": "Cursor版本 < 0.45.0跳过getMachineId修补",
"detecting_version": "檢測Cursor版本",
"patching_getmachineid": "修補getMachineId",
"version_greater_than_0_45": "Cursor版本 >= 0.45.0修補getMachineId"
},
"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 驗證",
"no_turnstile": "未檢測到 Turnstile 驗證",
"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": "檢測到登錄頁面,開始登錄...",
@@ -126,7 +112,12 @@
"update_cursor_auth_info": "更新Cursor認證信息",
"setting_password": "設置密碼",
"manual_code_input": "手動輸入驗證碼",
"manual_email_input": "手動輸入郵箱地址"
"manual_email_input": "手動輸入郵箱地址",
"password": "密碼",
"first_name": "名字",
"last_name": "姓氏",
"exit_signal": "退出信號",
"email_address": "郵箱地址"
},
"auth": {
"title": "Cursor 認證管理器",
@@ -143,7 +134,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": "生成新郵箱",
@@ -178,7 +172,7 @@
},
"email": {
"starting_browser": "啟動瀏覽器",
"visiting_site": "訪問 smailpro.com",
"visiting_site": "訪問 mail.tm",
"create_success": "郵箱創建成功",
"create_failed": "郵箱創建失敗",
"create_error": "郵箱創建錯誤: {error}",
@@ -192,7 +186,44 @@
"verification_code_found": "找到驗證碼",
"verification_code_not_found": "未找到驗證碼",
"verification_code_error": "驗證碼錯誤: {error}",
"address": "郵箱地址"
}
"address": "郵箱地址",
"all_domains_blocked": "所有域名都被屏蔽了,切換服務",
"no_available_domains_after_filtering": "過濾後沒有可用域名",
"switching_service": "切換到 {service} 服務",
"domains_list_error": "獲取域名列表失敗: {error}",
"failed_to_get_available_domains": "獲取可用域名失敗",
"domains_excluded": "排除的域名: {domains}",
"failed_to_create_account": "創建帳戶失敗",
"account_creation_error": "帳戶創建錯誤: {error}",
"blocked_domains": "被屏蔽的域名: {domains}",
"blocked_domains_loaded": "加載被屏蔽的域名: {domains}",
"blocked_domains_loaded_error": "加載被屏蔽的域名失敗: {error}",
"blocked_domains_loaded_success": "加載被屏蔽的域名成功",
"blocked_domains_loaded_timeout": "加載被屏蔽的域名超時: {timeout}秒",
"blocked_domains_loaded_timeout_error": "加載被屏蔽的域名超時錯誤: {error}",
"available_domains_loaded": "獲取到 {count} 個可用域名",
"domains_filtered": "過濾後剩餘 {count} 個可用域名",
"trying_to_create_email": "嘗試創建郵箱: {email}"
},
"update": {
"title": "禁用 Cursor 自动更新",
"disable_success": "自動更新禁用成功",
"disable_failed": "禁用自動更新失敗: {error}",
"press_enter": "按回車鍵退出",
"start_disable": "開始禁用自動更新",
"killing_processes": "殺死進程",
"processes_killed": "進程已殺死",
"removing_directory": "刪除目錄",
"directory_removed": "目錄已刪除",
"creating_block_file": "創建阻止文件",
"block_file_created": "阻止文件已創建"
},
"updater": {
"checking": "檢查更新...",
"new_version_available": "有新版本可用! (當前版本: {current}, 最新版本: {latest})",
"updating": "正在更新到最新版本。程序將自動重啟。",
"up_to_date": "您使用的是最新版本。",
"check_failed": "檢查更新失敗: {error}",
"continue_anyway": "繼續使用當前版本..."
}
}

12
logo.py
View File

@@ -2,17 +2,17 @@ from colorama import Fore, Style, init
from dotenv import load_dotenv
import os
# 獲取當前腳本所在目錄
# Get the current script directory
current_dir = os.path.dirname(os.path.abspath(__file__))
# 構建.env文件的完整路徑
# Build the full path to the .env file
env_path = os.path.join(current_dir, '.env')
# 加載環境變量,指定.env文件路徑
# Load environment variables, specifying the .env file path
load_dotenv(env_path)
# 獲取版本號,如果未找到則使用默認值
# Get the version number, using the default value if not found
version = os.getenv('VERSION', '1.0.0')
# 初始化 colorama
# Initialize colorama
init()
CURSOR_LOGO = f"""
@@ -27,6 +27,8 @@ CURSOR_LOGO = f"""
Pro Version Activator v{version}
{Fore.GREEN}
Author: Pin Studios | yeongpin
Github: https://github.com/yeongpin/cursor-free-vip
{Fore.RED}
Press 5 to change language | 按下 5 键切换语言
{Style.RESET_ALL}

268
main.py
View File

@@ -3,8 +3,18 @@
import os
import sys
import json
from logo import print_logo
from logo import print_logo, version
from colorama import Fore, Style, init
import locale
import platform
import requests
import subprocess
# 只在 Windows 系统上导入 windll
if platform.system() == 'Windows':
import ctypes
# 只在 Windows 上导入 windll
from ctypes import windll
# 初始化colorama
init()
@@ -19,48 +29,144 @@ EMOJI = {
"RESET": "🔄",
"MENU": "📋",
"ARROW": "",
"LANG": "🌐"
"LANG": "🌐",
"UPDATE": "🔄"
}
class Translator:
def __init__(self):
self.current_language = 'zh_tw' # 默认语言
self.translations = {}
self.current_language = self.detect_system_language() # 使用正确的方法名
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')
def detect_system_language(self):
"""Detect system language and return corresponding language code"""
try:
system = platform.system()
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 system == 'Windows':
return self._detect_windows_language()
else:
return self._detect_unix_language()
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Failed to detect system language: {e}{Style.RESET_ALL}")
return 'en'
def _detect_windows_language(self):
"""Detect language on Windows systems"""
try:
# 确保我们在 Windows 上
if platform.system() != 'Windows':
return 'en'
# 获取键盘布局
user32 = ctypes.windll.user32
hwnd = user32.GetForegroundWindow()
threadid = user32.GetWindowThreadProcessId(hwnd, 0)
layout_id = user32.GetKeyboardLayout(threadid) & 0xFFFF
# Map language ID to our language codes
language_map = {
0x0409: 'en', # English
0x0404: 'zh_tw', # Traditional Chinese
0x0804: 'zh_cn', # Simplified Chinese
}
return language_map.get(layout_id, 'en')
except:
return self._detect_unix_language()
def _detect_unix_language(self):
"""Detect language on Unix-like systems (Linux, macOS)"""
try:
# Get the system locale
system_locale = locale.getdefaultlocale()[0]
if not system_locale:
return 'en'
system_locale = system_locale.lower()
# Map locale to our language codes
if system_locale.startswith('zh_tw') or system_locale.startswith('zh_hk'):
return 'zh_tw'
elif system_locale.startswith('zh_cn'):
return 'zh_cn'
elif system_locale.startswith('en'):
return 'en'
# Try to get language from LANG environment variable as fallback
env_lang = os.getenv('LANG', '').lower()
if 'tw' in env_lang or 'hk' in env_lang:
return 'zh_tw'
elif 'cn' in env_lang:
return 'zh_cn'
return 'en'
except:
return 'en'
def load_translations(self):
"""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')
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()
@@ -74,36 +180,117 @@ def print_menu():
print(f"{Fore.GREEN}3{Style.RESET_ALL}. {EMOJI['SUCCESS']} {translator.get('menu.register_manual')}")
print(f"{Fore.GREEN}4{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.quit')}")
print(f"{Fore.GREEN}5{Style.RESET_ALL}. {EMOJI['LANG']} {translator.get('menu.select_language')}")
print(f"{Fore.GREEN}6{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.disable_auto_update')}")
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 check_latest_version():
"""Check if current version matches the latest release version"""
try:
print(f"\n{Fore.CYAN}{EMOJI['UPDATE']} {translator.get('updater.checking')}{Style.RESET_ALL}")
# Get latest version from GitHub API with timeout and proper headers
headers = {
'Accept': 'application/vnd.github.v3+json',
'User-Agent': 'CursorFreeVIP-Updater'
}
response = requests.get(
"https://api.github.com/repos/yeongpin/cursor-free-vip/releases/latest",
headers=headers,
timeout=10
)
# Check if response is successful
if response.status_code != 200:
raise Exception(f"GitHub API returned status code {response.status_code}")
response_data = response.json()
if "tag_name" not in response_data:
raise Exception("No version tag found in GitHub response")
latest_version = response_data["tag_name"].lstrip('v')
# Validate version format
if not latest_version:
raise Exception("Invalid version format received")
if latest_version != version:
print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.new_version_available', current=version, latest=latest_version)}{Style.RESET_ALL}")
try:
# Execute update command based on platform
if platform.system() == 'Windows':
update_command = 'irm https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/install.ps1 | iex'
subprocess.run(['powershell', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', update_command], check=True)
else:
# For Linux/Mac, download and execute the install script
install_script_url = 'https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/install.sh'
# First verify the script exists
script_response = requests.get(install_script_url, timeout=5)
if script_response.status_code != 200:
raise Exception("Installation script not found")
# Save and execute the script
with open('install.sh', 'wb') as f:
f.write(script_response.content)
os.chmod('install.sh', 0o755) # Make executable
subprocess.run(['./install.sh'], check=True)
# Clean up
if os.path.exists('install.sh'):
os.remove('install.sh')
print(f"\n{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('updater.updating')}{Style.RESET_ALL}")
sys.exit(0)
except Exception as update_error:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('updater.update_failed', error=str(update_error))}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.manual_update_required')}{Style.RESET_ALL}")
return
else:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('updater.up_to_date')}{Style.RESET_ALL}")
except requests.exceptions.RequestException as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('updater.network_error', error=str(e))}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.continue_anyway')}{Style.RESET_ALL}")
return
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('updater.check_failed', error=str(e))}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('updater.continue_anyway')}{Style.RESET_ALL}")
return
def main():
print_logo()
check_latest_version() # Add version check before showing menu
print_menu()
while True:
try:
choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices='0-5')}: {Style.RESET_ALL}")
choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices='0-6')}: {Style.RESET_ALL}")
if choice == "0":
print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.exit')}...{Style.RESET_ALL}")
@@ -112,23 +299,27 @@ def main():
elif choice == "1":
import reset_machine_manual
reset_machine_manual.run(translator)
break
print_menu()
elif choice == "2":
import cursor_register
cursor_register.main(translator)
break
print_menu()
elif choice == "3":
import cursor_register_manual
cursor_register_manual.main(translator)
break
print_menu()
elif choice == "4":
import quit_cursor
quit_cursor.quit_cursor(translator)
break
print_menu()
elif choice == "5":
if select_language():
print_menu()
continue
elif choice == "6":
import disable_auto_update
disable_auto_update.run(translator)
print_menu()
else:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
print_menu()
@@ -139,10 +330,7 @@ def main():
return
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.error_occurred', error=str(e))}{Style.RESET_ALL}")
break
print(f"\n{Fore.CYAN}{'' * 50}{Style.RESET_ALL}")
input(f"{EMOJI['INFO']} {translator.get('menu.press_enter')}...{Style.RESET_ALL}")
print_menu()
if __name__ == "__main__":
main()
main()

View File

@@ -100,6 +100,9 @@ def setup_driver(translator=None):
# 使用无痕模式
co.set_argument("--incognito")
# 设置随机端口
co.set_argument("--no-sandbox")
# 设置随机端口
co.auto_port()
@@ -243,7 +246,7 @@ def fill_password(page, password, translator=None):
if translator:
print(f"{Fore.CYAN}🔑 {translator.get('register.setting_password')}{Style.RESET_ALL}")
else:
print("\n正在设置密码...")
print(f"\n{translator.get('register.setting_password')}")
password_input = page.ele("@name=password")
if password_input:
password_input.input(password)
@@ -257,14 +260,14 @@ def fill_password(page, password, translator=None):
if translator:
print(f"{Fore.GREEN}{translator.get('register.password_success')}{Style.RESET_ALL}")
else:
print(f"密码设置完成: {password}")
print(f"{translator.get('register.password_success')}: {password}")
return True
except Exception as e:
if translator:
print(f"{Fore.RED}{translator.get('register.password_error', error=str(e))}{Style.RESET_ALL}")
else:
print(f"设置密码时出错: {e}")
print(f"{translator.get('register.password_error')}: {e}")
return False
def handle_verification_code(browser_tab, email_tab, controller, email, password, translator=None):
@@ -273,7 +276,7 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
if translator:
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
else:
print("\n等待并获取验证码...")
print(f"\n{translator.get('register.waiting_for_verification_code')}")
# 检查是否使用手动输入验证码
if hasattr(controller, 'get_verification_code') and email_tab is None: # 手动模式
@@ -284,7 +287,7 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
browser_tab.ele(f"@data-index={i}").input(digit)
time.sleep(random.uniform(0.1, 0.3))
print("验证码填写完成")
print(f"{translator.get('register.verification_success')}")
time.sleep(3)
# 处理最后一次 Turnstile 验证
@@ -292,11 +295,11 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
if translator:
print(f"{translator.get('register.verification_success')}")
else:
print("最后一次验证通过!")
print(f"{translator.get('register.verification_success')}")
time.sleep(2)
# 访问设置页面
print("访问设置页面...")
print(f"{translator.get('register.visiting_url')}: https://www.cursor.com/settings")
browser_tab.get("https://www.cursor.com/settings")
time.sleep(3) # 等待页面加载
return True, browser_tab
@@ -305,7 +308,7 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
# 自动获取验证码逻辑
elif email_tab:
print("等待验证码邮件...")
print(f"{translator.get('register.waiting_for_verification_code')}")
time.sleep(5) # 等待验证码邮件
# 使用已有的 email_tab 刷新邮箱

View File

@@ -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,121 +13,236 @@ 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
self.blocked_domains = self.get_blocked_domains()
def get_extension_block(self):
"""获取插件路径"""
root_dir = os.getcwd()
extension_path = os.path.join(root_dir, "PBlock")
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):
"""设置浏览器"""
def get_blocked_domains(self):
"""Get blocked domains list"""
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:
block_url = "https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/block_domain.txt"
response = requests.get(block_url, timeout=5)
if response.status_code == 200:
# Split text and remove empty lines
domains = [line.strip() for line in response.text.split('\n') if line.strip()]
if self.translator:
print(f"{Fore.YELLOW} {self.translator.get('email.extension_load_error')}: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.CYAN} {self.translator.get('email.blocked_domains_loaded', count=len(domains))}{Style.RESET_ALL}")
else:
print(f"{Fore.YELLOW} 加载插件失败: {str(e)}{Style.RESET_ALL}")
self.page = ChromiumPage(co)
return True
print(f"{Fore.CYAN} 加载 {len(domains)} 个被屏蔽的域名{Style.RESET_ALL}")
return domains
return []
except Exception as e:
if self.translator:
print(f"{Fore.RED} {self.translator.get('email.browser_start_error')}: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.blocked_domains_error', error=str(e))}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}❌ 启动浏览器失败: {str(e)}{Style.RESET_ALL}")
return False
print(f"{Fore.YELLOW}⚠️ 获取被屏蔽域名列表失败: {str(e)}{Style.RESET_ALL}")
return []
def exclude_blocked_domains(self, domains):
"""Exclude blocked domains"""
if not self.blocked_domains:
return domains
def create_email(self):
"""创建临时邮箱"""
try:
if self.translator:
print(f"{Fore.CYAN} {self.translator.get('email.visiting_site')}{Style.RESET_ALL}")
else:
print(f"{Fore.CYAN} 正在访问 smailpro.com...{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)
filtered_domains = []
for domain in domains:
if domain['domain'] not in self.blocked_domains:
filtered_domains.append(domain)
# 点击弹窗中的 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
excluded_count = len(domains) - len(filtered_domains)
if excluded_count > 0:
if self.translator:
print(f"{Fore.RED} {self.translator.get('email.create_failed')}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.domains_excluded', domains=excluded_count)}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}❌ 创建邮箱失败{Style.RESET_ALL}")
return None
except Exception as e:
if self.translator:
print(f"{Fore.RED}{self.translator.get('email.create_error')}: {str(e)}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}❌ 创建邮箱出错: {str(e)}{Style.RESET_ALL}")
return None
print(f"{Fore.YELLOW}⚠️ 已排除 {excluded_count} 个被屏蔽的域名{Style.RESET_ALL}")
return filtered_domains
def _generate_credentials(self):
"""generate random username and password"""
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
def create_email(self):
"""create temporary email"""
max_retries = 3 # Maximum number of retries
attempt = 0 # Current attempt count
while attempt < max_retries:
attempt += 1
try:
if self.translator:
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} 正在访问 {self.selected_service['name']}...{Style.RESET_ALL}")
# 获取可用域名列表
try:
domains_response = requests.get(f"{self.api_url}/domains", timeout=10)
if domains_response.status_code != 200:
print(f"{Fore.RED}{self.translator.get('email.domains_list_error', error=domains_response.status_code)}{Style.RESET_ALL}")
print(f"{Fore.RED}{self.translator.get('email.domains_list_error', error=domains_response.text)}{Style.RESET_ALL}")
raise Exception(f"{self.translator.get('email.failed_to_get_available_domains') if self.translator else 'Failed to get available domains'}")
domains = domains_response.json()["hydra:member"]
print(f"{Fore.CYAN} {self.translator.get('email.available_domains_loaded', count=len(domains))}{Style.RESET_ALL}")
if not domains:
raise Exception(f"{self.translator.get('email.no_available_domains') if self.translator else '没有可用域名'}")
except Exception as e:
print(f"{Fore.RED}❌ 获取域名列表时出错: {str(e)}{Style.RESET_ALL}")
raise
# 排除被屏蔽的域名
try:
filtered_domains = self.exclude_blocked_domains(domains)
if self.translator:
print(f"{Fore.CYAN} {self.translator.get('email.domains_filtered', count=len(filtered_domains))}{Style.RESET_ALL}")
else:
print(f"{Fore.CYAN} 过滤后剩余 {len(filtered_domains)} 个可用域名{Style.RESET_ALL}")
if not filtered_domains:
if self.translator:
print(f"{Fore.RED}{self.translator.get('email.all_domains_blocked')}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}❌ 所有域名都被屏蔽了,尝试切换服务{Style.RESET_ALL}")
# 切换到另一个服务
for service in self.services:
if service["api_url"] != self.api_url:
self.selected_service = service
self.api_url = service["api_url"]
if self.translator:
print(f"{Fore.CYAN} {self.translator.get('email.switching_service', service=service['name'])}{Style.RESET_ALL}")
else:
print(f"{Fore.CYAN} 切换到 {service['name']} 服务{Style.RESET_ALL}")
return self.create_email() # 递归调用
raise Exception(f"{self.translator.get('email.no_available_domains_after_filtering') if self.translator else '过滤后没有可用域名'}")
except Exception as e:
print(f"{Fore.RED}❌ 过滤域名时出错: {str(e)}{Style.RESET_ALL}")
raise
# 生成随机用户名和密码
try:
username, password = self._generate_credentials()
self.password = password
# 创建邮箱账户
selected_domain = filtered_domains[0]['domain']
email = f"{username}@{selected_domain}"
if self.translator:
print(f"{Fore.CYAN} {self.translator.get('email.trying_to_create_email', email=email)}{Style.RESET_ALL}")
else:
print(f"{Fore.CYAN} 尝试创建邮箱: {email}{Style.RESET_ALL}")
account_data = {
"address": email,
"password": password
}
except Exception as e:
print(f"{Fore.RED}❌ 生成凭据时出错: {str(e)}{Style.RESET_ALL}")
raise
# 创建账户
try:
create_response = requests.post(f"{self.api_url}/accounts", json=account_data, timeout=15)
if create_response.status_code != 201:
if self.translator:
print(f"{Fore.RED}{self.translator.get('email.failed_to_create_account', error=create_response.status_code)}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}❌ 创建账户失败: 状态码 {create_response.status_code}{Style.RESET_ALL}")
if self.translator:
print(f"{Fore.RED}{self.translator.get('email.failed_to_create_account', error=create_response.text)}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}❌ 响应内容: {create_response.text}{Style.RESET_ALL}")
# 如果是域名问题,尝试下一个域名
if len(filtered_domains) > 1 and ("domain" in create_response.text.lower() or "address" in create_response.text.lower()):
print(f"{Fore.YELLOW}⚠️ 尝试使用下一个可用域名...{Style.RESET_ALL}")
# 将当前域名添加到屏蔽列表
if selected_domain not in self.blocked_domains:
self.blocked_domains.append(selected_domain)
# 递归调用自己
return self.create_email()
raise Exception(f"{self.translator.get('email.failed_to_create_account') if self.translator else '创建账户失败'}")
except Exception as e:
if self.translator:
print(f"{Fore.RED}{self.translator.get('email.failed_to_create_account', error=str(e))}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}❌ 创建账户时出错: {str(e)}{Style.RESET_ALL}")
raise
# 获取访问令牌
try:
token_data = {
"address": email,
"password": password
}
token_response = requests.post(f"{self.api_url}/token", json=token_data, timeout=10)
if token_response.status_code != 200:
if self.translator:
print(f"{Fore.RED}{self.translator.get('email.failed_to_get_access_token', error=token_response.status_code)}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}❌ 获取令牌失败: 状态码 {token_response.status_code}{Style.RESET_ALL}")
if self.translator:
print(f"{Fore.RED}{self.translator.get('email.failed_to_get_access_token', error=token_response.text)}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}❌ 响应内容: {token_response.text}{Style.RESET_ALL}")
raise Exception(f"{self.translator.get('email.failed_to_get_access_token') if self.translator else '获取访问令牌失败'}")
self.token = token_response.json()["token"]
self.email = email
except Exception as e:
print(f"{Fore.RED}❌ 获取令牌时出错: {str(e)}{Style.RESET_ALL}")
raise
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
except Exception as e:
if attempt < max_retries:
print(f"{Fore.YELLOW}⚠️ 尝试重新创建邮箱... (尝试 {attempt}/{max_retries}){Style.RESET_ALL}")
else:
if self.translator:
print(f"{Fore.RED}{self.translator.get('email.create_error')}: {str(e)}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}❌ 创建邮箱出错: {str(e)}{Style.RESET_ALL}")
return None
def close(self):
"""关闭浏览器"""
"""close browser"""
if self.page:
self.page.quit()
def refresh_inbox(self):
"""刷新邮箱"""
"""refresh inbox"""
try:
if self.translator:
print(f"{Fore.CYAN}🔄 {self.translator.get('email.refreshing')}{Style.RESET_ALL}")
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 +250,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 +265,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:
@@ -172,18 +297,35 @@ class NewTempEmail:
return False
def get_verification_code(self):
"""获取验证码"""
"""get verification code"""
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 +365,4 @@ def main(translator=None):
temp_email.close()
if __name__ == "__main__":
main()
main()

View File

@@ -4,10 +4,10 @@ from colorama import Fore, Style, init
import sys
import os
# 初始化colorama
# Initialize colorama
init()
# 定义emoji常量
# Define emoji constants
EMOJI = {
"PROCESS": "⚙️",
"SUCCESS": "",
@@ -19,15 +19,15 @@ EMOJI = {
class CursorQuitter:
def __init__(self, timeout=5, translator=None):
self.timeout = timeout
self.translator = translator # 使用传入的翻译器
self.translator = translator # Use the passed translator
def quit_cursor(self):
"""温和地关闭 Cursor 进程"""
"""Gently close Cursor processes"""
try:
print(f"{Fore.CYAN}{EMOJI['PROCESS']} {self.translator.get('quit_cursor.start')}...{Style.RESET_ALL}")
cursor_processes = []
# 收集所有 Cursor 进程
# Collect all Cursor processes
for proc in psutil.process_iter(['pid', 'name']):
try:
if proc.info['name'].lower() in ['cursor.exe', 'cursor']:
@@ -39,7 +39,7 @@ class CursorQuitter:
print(f"{Fore.GREEN}{EMOJI['INFO']} {self.translator.get('quit_cursor.no_process')}{Style.RESET_ALL}")
return True
# 温和地请求进程终止
# Gently request processes to terminate
for proc in cursor_processes:
try:
if proc.is_running():
@@ -48,7 +48,7 @@ class CursorQuitter:
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
# 等待进程自然终止
# Wait for processes to terminate naturally
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('quit_cursor.waiting')}...{Style.RESET_ALL}")
start_time = time.time()
while time.time() - start_time < self.timeout:
@@ -66,7 +66,7 @@ class CursorQuitter:
time.sleep(0.5)
# 如果超时后仍有进程在运行
# If processes are still running after timeout
if still_running:
process_list = ", ".join([str(p.pid) for p in still_running])
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('quit_cursor.timeout', pids=process_list)}{Style.RESET_ALL}")
@@ -79,11 +79,11 @@ class CursorQuitter:
return False
def quit_cursor(translator=None, timeout=5):
"""便捷函数,用于直接调用退出功能"""
"""Convenient function for directly calling the quit function"""
quitter = CursorQuitter(timeout, translator)
return quitter.quit_cursor()
if __name__ == "__main__":
# 如果直接运行,使用默认翻译器
# If run directly, use the default translator
from main import translator as main_translator
quit_cursor(main_translator)

View File

@@ -11,10 +11,10 @@ import tempfile
from colorama import Fore, Style, init
from typing import Tuple
# 初始化colorama
# Initialize colorama
init()
# 定义emoji常量
# Define emoji constants
EMOJI = {
"FILE": "📄",
"BACKUP": "💾",
@@ -25,7 +25,7 @@ EMOJI = {
}
def get_cursor_paths(translator=None) -> Tuple[str, str]:
"""根据不同操作系统获取 Cursor 相关路径"""
""" Get Cursor related paths"""
system = platform.system()
paths_map = {
@@ -65,7 +65,7 @@ def get_cursor_paths(translator=None) -> Tuple[str, str]:
)
def version_check(version: str, min_version: str = "", max_version: str = "", translator=None) -> bool:
"""版本号检查"""
"""Version number check"""
version_pattern = r"^\d+\.\d+\.\d+$"
try:
if not re.match(version_pattern, version):
@@ -92,7 +92,7 @@ def version_check(version: str, min_version: str = "", max_version: str = "", tr
return False
def check_cursor_version(translator) -> bool:
"""检查 Cursor 版本"""
"""Check Cursor version"""
try:
pkg_path, _ = get_cursor_paths(translator)
with open(pkg_path, "r", encoding="utf-8") as f:
@@ -103,7 +103,7 @@ def check_cursor_version(translator) -> bool:
return False
def modify_main_js(main_path: str, translator) -> bool:
"""修改 main.js 文件"""
"""Modify main.js file"""
try:
original_stat = os.stat(main_path)
original_mode = original_stat.st_mode
@@ -142,14 +142,14 @@ def modify_main_js(main_path: str, translator) -> bool:
return False
def patch_cursor_get_machine_id(translator) -> bool:
"""修补 Cursor getMachineId 函数"""
"""Patch Cursor getMachineId function"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.start_patching')}...{Style.RESET_ALL}")
# 获取路径
# Get paths
pkg_path, main_path = get_cursor_paths(translator)
# 检查文件权限
# Check file permissions
for file_path in [pkg_path, main_path]:
if not os.path.isfile(file_path):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.file_not_found', path=file_path)}{Style.RESET_ALL}")
@@ -158,7 +158,7 @@ def patch_cursor_get_machine_id(translator) -> bool:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.no_write_permission', path=file_path)}{Style.RESET_ALL}")
return False
# 获取版本号
# Get version number
try:
with open(pkg_path, "r", encoding="utf-8") as f:
version = json.load(f)["version"]
@@ -167,20 +167,20 @@ def patch_cursor_get_machine_id(translator) -> bool:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.read_version_failed', error=str(e))}{Style.RESET_ALL}")
return False
# 检查版本
# Check version
if not version_check(version, min_version="0.45.0", translator=translator):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_not_supported')}{Style.RESET_ALL}")
return False
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.version_check_passed')}{Style.RESET_ALL}")
# 备份文件
# Backup file
backup_path = main_path + ".bak"
if not os.path.exists(backup_path):
shutil.copy2(main_path, backup_path)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.backup_created', path=backup_path)}{Style.RESET_ALL}")
# 修改文件
# Modify file
if not modify_main_js(main_path, translator):
return False
@@ -195,7 +195,7 @@ class MachineIDResetter:
def __init__(self, translator=None):
self.translator = translator
# 判断操作系统
# Check operating system
if sys.platform == "win32": # Windows
appdata = os.getenv("APPDATA")
if appdata is None:
@@ -224,17 +224,17 @@ class MachineIDResetter:
raise NotImplementedError(f"Not Supported OS: {sys.platform}")
def generate_new_ids(self):
"""生成新的机器ID"""
# 生成新的UUID
"""Generate new machine ID"""
# Generate new UUID
dev_device_id = str(uuid.uuid4())
# 生成新的machineId (64个字符的十六进制)
# Generate new machineId (64 characters of hexadecimal)
machine_id = hashlib.sha256(os.urandom(32)).hexdigest()
# 生成新的macMachineId (128个字符的十六进制)
# Generate new macMachineId (128 characters of hexadecimal)
mac_machine_id = hashlib.sha512(os.urandom(64)).hexdigest()
# 生成新的sqmId
# Generate new sqmId
sqm_id = "{" + str(uuid.uuid4()).upper() + "}"
return {
@@ -242,11 +242,11 @@ class MachineIDResetter:
"telemetry.macMachineId": mac_machine_id,
"telemetry.machineId": machine_id,
"telemetry.sqmId": sqm_id,
"storage.serviceMachineId": dev_device_id, # 添加 storage.serviceMachineId
"storage.serviceMachineId": dev_device_id, # Add storage.serviceMachineId
}
def update_sqlite_db(self, new_ids):
"""更新 SQLite 数据库中的机器ID"""
"""Update machine ID in SQLite database"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.updating_sqlite')}...{Style.RESET_ALL}")
@@ -281,7 +281,7 @@ class MachineIDResetter:
return False
def update_system_ids(self, new_ids):
"""更新系统级别的ID"""
"""Update system-level IDs"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.updating_system_ids')}...{Style.RESET_ALL}")
@@ -297,7 +297,7 @@ class MachineIDResetter:
return False
def _update_windows_machine_guid(self):
"""更新Windows MachineGuid"""
"""Update Windows MachineGuid"""
try:
import winreg
key = winreg.OpenKey(
@@ -318,11 +318,11 @@ class MachineIDResetter:
raise
def _update_macos_platform_uuid(self, new_ids):
"""更新macOS Platform UUID"""
"""Update macOS Platform UUID"""
try:
uuid_file = "/var/root/Library/Preferences/SystemConfiguration/com.apple.platform.uuid.plist"
if os.path.exists(uuid_file):
# 使用sudo来执行plutil命令
# Use sudo to execute plutil command
cmd = f'sudo plutil -replace "UUID" -string "{new_ids["telemetry.macMachineId"]}" "{uuid_file}"'
result = os.system(cmd)
if result == 0:
@@ -334,7 +334,7 @@ class MachineIDResetter:
raise
def reset_machine_ids(self):
"""重置机器ID并备份原文件"""
"""Reset machine ID and backup original file"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.checking')}...{Style.RESET_ALL}")
@@ -360,26 +360,26 @@ class MachineIDResetter:
print(f"{Fore.CYAN}{EMOJI['RESET']} {self.translator.get('reset.generating')}...{Style.RESET_ALL}")
new_ids = self.generate_new_ids()
# 更新配置文件
# Update configuration file
config.update(new_ids)
print(f"{Fore.CYAN}{EMOJI['FILE']} {self.translator.get('reset.saving_json')}...{Style.RESET_ALL}")
with open(self.db_path, "w", encoding="utf-8") as f:
json.dump(config, f, indent=4)
# 更新SQLite数据库
# Update SQLite database
self.update_sqlite_db(new_ids)
# 更新系统ID
# Update system IDs
self.update_system_ids(new_ids)
# 检查 Cursor 版本并执行相应的操作
# Check Cursor version and perform corresponding actions
greater_than_0_45 = check_cursor_version(self.translator)
if greater_than_0_45:
print(f"{Fore.CYAN}{EMOJI['INFO']} 检测到 Cursor 版本 >= 0.45.0,正在修补 getMachineId...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.detecting_version')} >= 0.45.0{self.translator.get('reset.patching_getmachineid')}{Style.RESET_ALL}")
patch_cursor_get_machine_id(self.translator)
else:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Cursor 版本 < 0.45.0,跳过 getMachineId 修补{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('reset.version_less_than_0_45')}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.success')}{Style.RESET_ALL}")
print(f"\n{Fore.CYAN}{self.translator.get('reset.new_id')}:{Style.RESET_ALL}")
@@ -397,12 +397,12 @@ class MachineIDResetter:
return False
def run(translator=None):
"""便捷函数,用于直接调用重置功能"""
"""Convenient function for directly calling the reset function"""
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['RESET']} {translator.get('reset.title')}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
resetter = MachineIDResetter(translator) # 正確傳遞 translator
resetter = MachineIDResetter(translator) # Correctly pass translator
resetter.reset_machine_ids()
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")

View File

@@ -1,4 +1,4 @@
# 設置顏色主題
# set color theme
$Theme = @{
Primary = 'Cyan'
Success = 'Green'
@@ -17,7 +17,7 @@ $Logo = @"
"@
# 美化輸出函數
# Beautiful Output Function
function Write-Styled {
param (
[string]$Message,
@@ -40,7 +40,7 @@ function Write-Styled {
}
}
# 獲取版本號函數
# Get version number function
function Get-LatestVersion {
try {
$latestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/yeongpin/cursor-free-vip/releases/latest"
@@ -54,28 +54,28 @@ function Get-LatestVersion {
}
}
# 顯示 Logo
# Show Logo
Write-Host $Logo -ForegroundColor $Theme.Primary
$releaseInfo = Get-LatestVersion
$version = $releaseInfo.Version
Write-Host "Version $version" -ForegroundColor $Theme.Info
Write-Host "Created by YeongPin`n" -ForegroundColor $Theme.Info
# 設置 TLS 1.2
# Set TLS 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# 主安裝函數
# Main installation function
function Install-CursorFreeVIP {
Write-Styled "Start downloading Cursor Free VIP" -Color $Theme.Primary -Prefix "Download"
try {
# 獲取最新版本
# Get latest version
Write-Styled "Checking latest version..." -Color $Theme.Primary -Prefix "Update"
$releaseInfo = Get-LatestVersion
$version = $releaseInfo.Version
Write-Styled "Found latest version: $version" -Color $Theme.Success -Prefix "Version"
# 查找對應的資源
# Find corresponding resources
$asset = $releaseInfo.Assets | Where-Object { $_.name -eq "CursorFreeVIP_${version}_windows.exe" }
if (!$asset) {
Write-Styled "File not found: CursorFreeVIP_${version}_windows.exe" -Color $Theme.Error -Prefix "Error"
@@ -86,22 +86,114 @@ function Install-CursorFreeVIP {
throw "Cannot find target file"
}
# 下載到Downloads文件夾
# Check if Downloads folder already exists for the corresponding version
$DownloadsPath = [Environment]::GetFolderPath("UserProfile") + "\Downloads"
$downloadPath = Join-Path $DownloadsPath "CursorFreeVIP.exe"
$downloadPath = Join-Path $DownloadsPath "CursorFreeVIP_${version}_windows.exe"
Write-Styled "Downloading to Downloads folder..." -Color $Theme.Primary -Prefix "Download"
if (Test-Path $downloadPath) {
Write-Styled "Found existing installation file" -Color $Theme.Success -Prefix "Found"
Write-Styled "Location: $downloadPath" -Color $Theme.Info -Prefix "Location"
# Check if running with administrator privileges
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Styled "Requesting administrator privileges..." -Color $Theme.Warning -Prefix "Admin"
# Create new process with administrator privileges
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
$startInfo.FileName = $downloadPath
$startInfo.UseShellExecute = $true
$startInfo.Verb = "runas"
try {
[System.Diagnostics.Process]::Start($startInfo)
Write-Styled "Program started with admin privileges" -Color $Theme.Success -Prefix "Launch"
return
}
catch {
Write-Styled "Failed to start with admin privileges. Starting normally..." -Color $Theme.Warning -Prefix "Warning"
Start-Process $downloadPath
return
}
}
# If already running with administrator privileges, start directly
Start-Process $downloadPath
return
}
Write-Styled "No existing installation file found, starting download..." -Color $Theme.Primary -Prefix "Download"
# Create WebClient and add progress event
$webClient = New-Object System.Net.WebClient
$webClient.Headers.Add("User-Agent", "PowerShell Script")
$webClient.DownloadFile($asset.browser_download_url, $downloadPath)
# Define progress variables
$Global:downloadedBytes = 0
$Global:totalBytes = 0
$Global:lastProgress = 0
$Global:lastBytes = 0
$Global:lastTime = Get-Date
# Download progress event
$eventId = [guid]::NewGuid()
Register-ObjectEvent -InputObject $webClient -EventName DownloadProgressChanged -Action {
$Global:downloadedBytes = $EventArgs.BytesReceived
$Global:totalBytes = $EventArgs.TotalBytesToReceive
$progress = [math]::Round(($Global:downloadedBytes / $Global:totalBytes) * 100, 1)
# Only update display when progress changes by more than 1%
if ($progress -gt $Global:lastProgress + 1) {
$Global:lastProgress = $progress
$downloadedMB = [math]::Round($Global:downloadedBytes / 1MB, 2)
$totalMB = [math]::Round($Global:totalBytes / 1MB, 2)
# Calculate download speed
$currentTime = Get-Date
$timeSpan = ($currentTime - $Global:lastTime).TotalSeconds
if ($timeSpan -gt 0) {
$bytesChange = $Global:downloadedBytes - $Global:lastBytes
$speed = $bytesChange / $timeSpan
# Choose appropriate unit based on speed
$speedDisplay = if ($speed -gt 1MB) {
"$([math]::Round($speed / 1MB, 2)) MB/s"
} elseif ($speed -gt 1KB) {
"$([math]::Round($speed / 1KB, 2)) KB/s"
} else {
"$([math]::Round($speed, 2)) B/s"
}
Write-Host "`rDownloading: $downloadedMB MB / $totalMB MB ($progress%) - $speedDisplay" -NoNewline -ForegroundColor Cyan
# Update last data
$Global:lastBytes = $Global:downloadedBytes
$Global:lastTime = $currentTime
}
}
} | Out-Null
# Download completed event
Register-ObjectEvent -InputObject $webClient -EventName DownloadFileCompleted -Action {
Write-Host "`r" -NoNewline
Write-Styled "Download completed!" -Color $Theme.Success -Prefix "Complete"
Unregister-Event -SourceIdentifier $eventId
} | Out-Null
# Start download
$webClient.DownloadFileAsync([Uri]$asset.browser_download_url, $downloadPath)
# Wait for download to complete
while ($webClient.IsBusy) {
Start-Sleep -Milliseconds 100
}
Write-Styled "Download completed!" -Color $Theme.Success -Prefix "Complete"
Write-Styled "File location: $downloadPath" -Color $Theme.Info -Prefix "Location"
Write-Styled "Starting program..." -Color $Theme.Primary -Prefix "Launch"
# 運行程序
# Run program
Start-Process $downloadPath
}
catch {
Write-Styled $_.Exception.Message -Color $Theme.Error -Prefix "Error"
@@ -109,7 +201,7 @@ function Install-CursorFreeVIP {
}
}
# 執行安裝
# Execute installation
try {
Install-CursorFreeVIP
}
@@ -120,4 +212,4 @@ catch {
finally {
Write-Host "`nPress any key to exit..." -ForegroundColor $Theme.Info
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
}
}

View File

@@ -1,6 +1,6 @@
#!/bin/bash
# 顏色定義
# Color definitions
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
@@ -22,7 +22,7 @@ EOF
echo -e "${NC}"
}
# 获取下载文件夹路径
# Get download folder path
get_downloads_dir() {
if [[ "$(uname)" == "Darwin" ]]; then
echo "$HOME/Downloads"
@@ -36,59 +36,139 @@ get_downloads_dir() {
fi
}
# 獲取最新版本
# Get latest version
get_latest_version() {
echo -e "${CYAN} 正在檢查最新版本...${NC}"
echo -e "${CYAN} Checking latest version...${NC}"
local latest_release
latest_release=$(curl -s https://api.github.com/repos/yeongpin/cursor-free-vip/releases/latest)
if [ $? -ne 0 ]; then
echo -e "${RED}無法獲取最新版本信息${NC}"
echo -e "${RED}Cannot get latest version information${NC}"
exit 1
fi
VERSION=$(echo "$latest_release" | grep -o '"tag_name": ".*"' | cut -d'"' -f4 | tr -d 'v')
echo -e "${GREEN}找到最新版本: ${VERSION}${NC}"
echo -e "${GREEN}Found latest version: ${VERSION}${NC}"
}
# 檢測系統類型
# Detect system type and architecture
detect_os() {
if [[ "$(uname)" == "Darwin" ]]; then
OS="mac"
else
# Detect macOS architecture
ARCH=$(uname -m)
if [[ "$ARCH" == "arm64" ]]; then
OS="mac_arm64"
echo -e "${CYAN} Detected macOS ARM64 architecture${NC}"
else
OS="mac_intel"
echo -e "${CYAN} Detected macOS Intel architecture${NC}"
fi
elif [[ "$(uname)" == "Linux" ]]; then
OS="linux"
echo -e "${CYAN} Detected Linux system${NC}"
else
# Assume Windows
OS="windows"
echo -e "${CYAN} Detected Windows system${NC}"
fi
}
# 下載並安裝
# Install and download
install_cursor_free_vip() {
local downloads_dir=$(get_downloads_dir)
local binary_name="CursorFreeVIP_${VERSION}_${OS}"
local binary_path="${downloads_dir}/cursor-free-vip"
local binary_path="${downloads_dir}/${binary_name}"
local download_url="https://github.com/yeongpin/cursor-free-vip/releases/download/v${VERSION}/${binary_name}"
echo -e "${CYAN} 正在下載到 ${downloads_dir}...${NC}"
# Check if file already exists
if [ -f "${binary_path}" ]; then
echo -e "${GREEN}✅ Found existing installation file${NC}"
echo -e "${CYAN} Location: ${binary_path}${NC}"
# Check if running as root
if [ "$EUID" -ne 0 ]; then
echo -e "${YELLOW}⚠️ Requesting administrator privileges...${NC}"
if command -v sudo >/dev/null 2>&1; then
echo -e "${CYAN} Starting program with sudo...${NC}"
sudo chmod +x "${binary_path}"
sudo "${binary_path}"
else
echo -e "${YELLOW}⚠️ sudo not found, trying to run normally...${NC}"
chmod +x "${binary_path}"
"${binary_path}"
fi
else
# Already running as root
echo -e "${CYAN} Already running as root, starting program...${NC}"
chmod +x "${binary_path}"
"${binary_path}"
fi
return
fi
echo -e "${CYAN} No existing installation file found, starting download...${NC}"
echo -e "${CYAN} Downloading to ${downloads_dir}...${NC}"
echo -e "${CYAN} Download link: ${download_url}${NC}"
# Check if file exists
if curl --output /dev/null --silent --head --fail "$download_url"; then
echo -e "${GREEN}✅ File exists, starting download...${NC}"
else
echo -e "${RED}❌ Download link does not exist: ${download_url}${NC}"
echo -e "${YELLOW}⚠️ Trying without architecture...${NC}"
# Try without architecture
if [[ "$OS" == "mac_arm64" || "$OS" == "mac_intel" ]]; then
OS="mac"
binary_name="CursorFreeVIP_${VERSION}_${OS}"
download_url="https://github.com/yeongpin/cursor-free-vip/releases/download/v${VERSION}/${binary_name}"
echo -e "${CYAN} New download link: ${download_url}${NC}"
if ! curl --output /dev/null --silent --head --fail "$download_url"; then
echo -e "${RED}❌ New download link does not exist${NC}"
exit 1
fi
else
exit 1
fi
fi
# Download file
if ! curl -L -o "${binary_path}" "$download_url"; then
echo -e "${RED}下載失敗${NC}"
echo -e "${RED}Download failed${NC}"
exit 1
fi
echo -e "${CYAN} 正在設置執行權限...${NC}"
# Check downloaded file size
local file_size=$(stat -f%z "${binary_path}" 2>/dev/null || stat -c%s "${binary_path}" 2>/dev/null)
echo -e "${CYAN} Downloaded file size: ${file_size} bytes${NC}"
# If file is too small, it might be an error message
if [ "$file_size" -lt 1000 ]; then
echo -e "${YELLOW}⚠️ Warning: Downloaded file is too small, possibly not a valid executable file${NC}"
echo -e "${YELLOW}⚠️ File content:${NC}"
cat "${binary_path}"
echo ""
echo -e "${RED}❌ Download failed, please check version and operating system${NC}"
exit 1
fi
echo -e "${CYAN} Setting executable permissions...${NC}"
chmod +x "${binary_path}"
if [ $? -eq 0 ]; then
echo -e "${GREEN}安裝完成!${NC}"
echo -e "${CYAN} 程序已下載到: ${binary_path}${NC}"
echo -e "${CYAN} 正在啟動程序...${NC}"
echo -e "${GREEN}Installation completed!${NC}"
echo -e "${CYAN} Program downloaded to: ${binary_path}${NC}"
echo -e "${CYAN} Starting program...${NC}"
# 直接运行程序
# Run program directly
"${binary_path}"
else
echo -e "${RED}安裝失敗${NC}"
echo -e "${RED}Installation failed${NC}"
exit 1
fi
}
# 主程序
# Main program
main() {
print_logo
get_latest_version
@@ -96,5 +176,5 @@ main() {
install_cursor_free_vip
}
# 運行主程序
main
# Run main program
main