Compare commits

..

33 Commits

Author SHA1 Message Date
yeongpin
a3dff87da9 Enhance GitHub Actions workflow by adding code checkout step, calculating SHA256 checksums for release files, and extracting release notes from CHANGELOG. The release notes now include checksums for better transparency. 2025-04-15 10:41:46 +08:00
yeongpin
861f258ce4 Update CHANGELOG.md to reflect new version 1.9.04, including multiple fixes for package issues, readme formatting, and exception handling. 2025-04-15 10:33:08 +08:00
Pin Studios
ab9202fe48 Merge pull request #631 from xbhel/main
Fix ChromiumOptions.arguments type error: list object has no attribute 'get'
2025-04-15 10:28:41 +08:00
Pin Studios
d60c46bac6 Merge pull request #630 from canmi21/main
update: aur release 1.9.04 & fix(linux): pkg name & fix(chrome): oauth error
2025-04-15 10:27:43 +08:00
Pin Studios
4757f9777a Merge branch 'main' of https://github.com/canmi21/cursor into pr/597 2025-04-15 10:24:08 +08:00
Pin Studios
caecbd4c8d fix(readme): format download links for browsers 2025-04-15 10:24:07 +08:00
Canmi
105b5d4517 fix: github ouath fail error 2025-04-15 00:00:14 +08:00
Canmi
f325690e32 add: more output 2025-04-14 23:48:25 +08:00
Canmi
3de2db74b2 fix: unexpected 2025-04-14 23:32:49 +08:00
Canmi
6153041607 fix: handle 2025-04-14 23:22:56 +08:00
Canmi
6eba95c055 fix: oauth logic, add more debug output 2025-04-14 23:05:10 +08:00
Canmi
21535104a6 fix: google-chrome-stable on archlinx(linux), killall, port, and debug 2025-04-14 23:04:43 +08:00
Canmi
b42b4b01b9 fix: fetch 2025-04-14 22:02:10 +08:00
Canmi
4b9c465dd5 fix: path 2025-04-14 21:49:54 +08:00
Canmi
b98059a476 fix: missspell 2025-04-14 21:41:16 +08:00
xbhel
56882f0663 Fix ChromiumOptions#arguments has no attribute 'get' 2025-04-14 21:16:26 +08:00
Canmi
0852472746 fix: conflict 2025-04-14 21:10:56 +08:00
Canmi
d867f5cfe9 update: SRCINFO 2025-04-14 21:02:50 +08:00
Canmi
e69e500e8d add: LICENSE install 2025-04-14 21:02:34 +08:00
Canmi
2f012b9dc5 fix: missing LICENSE 2025-04-14 21:01:47 +08:00
Canmi
d3c6bf227b sync: aur version 2025-04-14 21:00:58 +08:00
Canmi
f697b71755 Merge branch 'yeongpin:main' into main 2025-04-14 20:59:13 +08:00
yeongpin
5863891f4b Merge branch 'main' of https://github.com/yeongpin/cursor-free-vip 2025-04-14 16:24:53 +08:00
yeongpin
7e0da4a0cb Update version to 1.9.05 and enhance CHANGELOG with new features, fixes, and Python version update in Docker container. 2025-04-14 16:24:50 +08:00
Pin Studios
1cdb543ea9 Merge pull request #613 from haroondilshad/fix/f-string-backslash-errors
fix:  An error occurred: f-string expression part cannot include a b…
2025-04-14 16:24:04 +08:00
Pin Studios
5dad4f35a6 Merge pull request #614 from wang93wei/main
refactor: 优化语言逻辑 + 升级 Linux arm64 Docker Python 版本至 3.10
2025-04-14 16:20:32 +08:00
Pin Studios
34a23a69a1 Update README.md 2025-04-14 15:24:40 +08:00
Pin Studios
3cca2e3b17 Update README.md 2025-04-14 15:01:06 +08:00
alanwang
ee287b91f2 ci: 更新 ARM64 Docker 容器中的 Python 版本至 3.10
将 ARM64 Docker 容器中的 Python 版本从 3.9 更新至 3.10,以使用最新的稳定版本并确保兼容性
2025-04-14 14:31:06 +08:00
Pin Studios
96704e9f38 Update README.md 2025-04-14 14:21:42 +08:00
haroondilshad
f541bc40b4 fix: An error occurred: f-string expression part cannot include a backslash (delete_cursor_google.py, line 243) 2025-04-14 08:20:55 +02:00
alanwang
a730b145a1 refactor: 使用match-case重构语言映射和菜单选择逻辑
将语言映射和菜单选择逻辑从if-elif重构为match-case,提高代码可读性和维护性
2025-04-14 14:18:58 +08:00
Canmi
9f81f94957 rm: duplicate content 2025-04-14 11:15:31 +08:00
11 changed files with 275 additions and 203 deletions

View File

@@ -1,10 +1,11 @@
pkgbase = cursor-free-vip-git pkgbase = cursor-free-vip-git
pkgdesc = Reset Cursor AI MachineID & Auto Sign Up / In & Bypass Higher Token Limit pkgdesc = Reset Cursor AI MachineID & Auto Sign Up / In & Bypass Higher Token Limit
pkgver = 1.9.03.2.g43a58db pkgver = 1.9.04.10.g5863891
pkgrel = 1 pkgrel = 1
url = https://github.com/yeongpin/cursor-free-vip url = https://github.com/yeongpin/cursor-free-vip
arch = x86_64 arch = x86_64
license = MIT license = MIT
license = Attribution-NonCommercial-NoDerivatives 4.0 International
makedepends = git makedepends = git
makedepends = python makedepends = python
makedepends = pyinstaller makedepends = pyinstaller
@@ -13,6 +14,8 @@ pkgbase = cursor-free-vip-git
depends = cursor-bin depends = cursor-bin
provides = cursor-free-vip provides = cursor-free-vip
source = cursor-free-vip::git+https://github.com/yeongpin/cursor-free-vip.git source = cursor-free-vip::git+https://github.com/yeongpin/cursor-free-vip.git
source = https://raw.githubusercontent.com/canmi21/openjlc/refs/heads/main/LICENSE
sha256sums = SKIP
sha256sums = SKIP sha256sums = SKIP
pkgname = cursor-free-vip-git pkgname = cursor-free-vip-git

4
.env
View File

@@ -1,2 +1,2 @@
version=1.9.04 version=1.9.05
VERSION=1.9.04 VERSION=1.9.05

View File

@@ -153,7 +153,7 @@ jobs:
- name: Build in ARM64 Docker container - name: Build in ARM64 Docker container
run: | run: |
docker run --rm --platform linux/arm64 -v ${{ github.workspace }}:/app -w /app arm64v8/python:3.9-slim bash -c " docker run --rm --platform linux/arm64 -v ${{ github.workspace }}:/app -w /app arm64v8/python:3.10-slim bash -c "
apt-get update && apt-get install -y build-essential apt-get update && apt-get install -y build-essential
pip install --upgrade pip pip install --upgrade pip
pip install pyinstaller pip install pyinstaller
@@ -211,6 +211,9 @@ jobs:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Get version - name: Get version
shell: bash shell: bash
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
@@ -220,18 +223,66 @@ jobs:
with: with:
path: artifacts path: artifacts
- name: Prepare release files - name: Calculate SHA256 checksums
run: | run: |
cd artifacts mkdir -p checksums
echo "Contents of artifacts directory:" for file in artifacts/CursorFreeVIP_${{ env.VERSION }}_windows.exe/CursorFreeVIP_${{ env.VERSION }}_windows.exe \
ls -la artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_arm64/CursorFreeVIP_${{ env.VERSION }}_mac_arm64 \
echo "Contents of subdirectories:" artifacts/CursorFreeVIP_${{ env.VERSION }}_linux_x64/CursorFreeVIP_${{ env.VERSION }}_linux_x64 \
ls -la */ artifacts/CursorFreeVIP_${{ env.VERSION }}_linux_arm64/CursorFreeVIP_${{ env.VERSION }}_linux_arm64 \
artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_intel/CursorFreeVIP_${{ env.VERSION }}_mac_intel
do
if [ -f "$file" ]; then
filename=$(basename $file)
sha256sum "$file" | cut -d ' ' -f 1 > checksums/${filename}.sha256
echo "${filename}: $(cat checksums/${filename}.sha256)" >> checksums/all_checksums.txt
else
echo "Warning: File $file not found"
fi
done
cat checksums/all_checksums.txt
- name: Extract release notes from CHANGELOG
run: |
version_pattern="## v${{ env.VERSION }}"
next_version_pattern="## v"
# Find the start line number of the current version
start_line=$(grep -n "$version_pattern" CHANGELOG.md | head -1 | cut -d: -f1)
if [ -z "$start_line" ]; then
echo "Error: Version ${{ env.VERSION }} not found in CHANGELOG.md"
exit 1
fi
# Find the line number of the next version
next_version_line=$(tail -n +$((start_line + 1)) CHANGELOG.md | grep -n "$next_version_pattern" | head -1 | cut -d: -f1)
if [ -z "$next_version_line" ]; then
# If there's no next version, get to the end of the file
changelog_content=$(tail -n +$start_line CHANGELOG.md)
else
# Extract content between current version and next version
end_line=$((start_line + next_version_line - 1))
changelog_content=$(sed -n "${start_line},${end_line}p" CHANGELOG.md)
fi
# Create release notes file
{
echo "$changelog_content"
echo ""
echo "## SHA256 Checksums"
cat checksums/all_checksums.txt
} > release_notes.md
# Display release notes for debugging
cat release_notes.md
- name: Create Release - name: Create Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
with: with:
tag_name: v${{ env.VERSION }} tag_name: v${{ env.VERSION }}
body_path: release_notes.md
files: | files: |
artifacts/CursorFreeVIP_${{ env.VERSION }}_windows.exe/CursorFreeVIP_${{ env.VERSION }}_windows.exe 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 }}_mac_arm64/CursorFreeVIP_${{ env.VERSION }}_mac_arm64

View File

@@ -1,5 +1,18 @@
# Change Log # Change Log
## v1.9.05
1. Refactor: Using match-case to refactor language mapping and menu selection logic, making the code clearer and more maintainable. | 使用 match-case 重构语言映射和菜单选择逻辑,使代码更清晰、可维护性更高。
2. Ci: Update the Python version in the ARM64 Docker build container to 3.10, making it more compatible and easier to migrate in the future. | 更新 ARM64 Docker 构建容器中的 Python 版本至 3.10,兼容性更强,方便未来迁移。
3. Fix: f-string backslash expression errors in multiple files | 修復多個文件中的 f-string 反斜杠表達式錯誤
4. Sync AUR new version 1.9.04 | 同步 AUR 新版本 1.9.04
5. Fix: missing license install on pkgbuild @michaeldavis246611119 mention here | 修復 pkgbuild 中缺少授權安裝 @michaeldavis246611119 提到這裡
6. Fix: readme table | 修復 readme 表格
7. Fix: google-chrome package name problem, add "google-chrome-stable" [Bug]: Chrome error | Arch | gnome | AUR chrome #242 [Discussion]: how to use the new feature, Register with Google Account #249 [Discussion]: Having issues using the script in Ubuntu #487 [Bug]: Can open chromium bin in linux #616 | 修復 google-chrome 包名稱問題,添加 "google-chrome-stable" [Bug]: Chrome error | Arch | gnome | AUR chrome #242 [Discussion]: how to use the new feature, Register with Google Account #249 [Discussion]: Having issues using the script in Ubuntu #487 [Bug]: Can open chromium bin in linux #616
8. Fix: exception error log | 修復異常錯誤日誌
9. Fix: github oauth error [Bug]: #564 | 修復 github oauth 錯誤 [Bug]: #564
10. Fix: ChromiumOptions.arguments type error: list object has no attribute 'get' | 修復 ChromiumOptions.arguments 類型錯誤list 對象沒有屬性 'get'
11. Fix: Some Issues | 修復一些問題
## v1.9.04 ## v1.9.04
1. Add: Opera GX Support | 添加 Opera GX 支持 1. Add: Opera GX Support | 添加 Opera GX 支持
2. Same as v1.9.03 | 與 v1.9.03 相同 2. Same as v1.9.03 | 與 v1.9.03 相同

View File

@@ -2,17 +2,17 @@
# Contributor: Canmi (Canmi21) # Contributor: Canmi (Canmi21)
pkgname=cursor-free-vip-git pkgname=cursor-free-vip-git
pkgver=1.9.03.2.g43a58db pkgver=1.9.04.10.g5863891
pkgrel=1 pkgrel=1
pkgdesc="Reset Cursor AI MachineID & Auto Sign Up / In & Bypass Higher Token Limit" pkgdesc="Reset Cursor AI MachineID & Auto Sign Up / In & Bypass Higher Token Limit"
arch=('x86_64') arch=('x86_64')
url="https://github.com/yeongpin/cursor-free-vip" url="https://github.com/yeongpin/cursor-free-vip"
license=('MIT') license=('MIT' 'Attribution-NonCommercial-NoDerivatives 4.0 International')
depends=('python' 'cursor-bin') depends=('python' 'cursor-bin')
makedepends=('git' 'python' 'pyinstaller' 'uv') makedepends=('git' 'python' 'pyinstaller' 'uv')
provides=('cursor-free-vip') provides=('cursor-free-vip')
source=("cursor-free-vip::git+https://github.com/yeongpin/cursor-free-vip.git") source=("cursor-free-vip::git+https://github.com/yeongpin/cursor-free-vip.git" "https://raw.githubusercontent.com/canmi21/openjlc/refs/heads/main/LICENSE")
sha256sums=('SKIP') sha256sums=('SKIP' 'SKIP')
pkgver() { pkgver() {
cd "$srcdir/cursor-free-vip" cd "$srcdir/cursor-free-vip"
@@ -28,5 +28,7 @@ build() {
} }
package() { package() {
install -Dm644 "$srcdir/LICENSE" "$pkgdir/usr/share/licenses/$pkgname/mit_license"
install -Dm644 "$srcdir/cursor-free-vip/LICENSE.md" "$pkgdir/usr/share/licenses/$pkgname/attribution_non_commercial_no_derivatives_license"
install -Dm755 "$srcdir/cursor-free-vip/dist/cursor-free-vip" "$pkgdir/usr/bin/cursor-free-vip" install -Dm755 "$srcdir/cursor-free-vip/dist/cursor-free-vip" "$pkgdir/usr/bin/cursor-free-vip"
} }

View File

@@ -7,10 +7,10 @@
<p align="center"> <p align="center">
[![Release](https://www.pinnumber.rr.nu/github/release/yeongpin/cursor-free-vip.svg)](https://github.com/yeongpin/cursor-free-vip/releases/latest) [![Release](https://img.shields.io/endpoint?url=https://www.pinnumber.rr.nu/badges/release/yeongpin/cursor-free-vip)](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/) [![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://www.pinnumber.rr.nu/github/stars/yeongpin/cursor-free-vip/stars.svg)](https://github.com/yeongpin/cursor-free-vip/stargazers) [![Stars](https://img.shields.io/endpoint?url=https://www.pinnumber.rr.nu/badges/stars/yeongpin/cursor-free-vip)](https://github.com/yeongpin/cursor-free-vip/stargazers)
[![Downloads](https://www.pinnumber.rr.nu/github/downloads/yeongpin/cursor-free-vip/total.svg)](https://github.com/yeongpin/cursor-free-vip/releases/latest) [![Downloads](https://img.shields.io/endpoint?url=https://www.pinnumber.rr.nu/badges/downloads/yeongpin/cursor-free-vip/total)](https://github.com/yeongpin/cursor-free-vip/releases/latest)
<a href="https://buymeacoffee.com/yeongpin" target="_blank"><img alt="Buy Me a Coffee" src="https://img.shields.io/badge/Buy%20Me%20a%20Coffee-Support%20Me-FFDA33"></a> <a href="https://buymeacoffee.com/yeongpin" target="_blank"><img alt="Buy Me a Coffee" src="https://img.shields.io/badge/Buy%20Me%20a%20Coffee-Support%20Me-FFDA33"></a>
</p> </p>
@@ -40,10 +40,10 @@ Always clean your browser's cache and cookies. If possible, use a VPN to create
</p> </p>
##### If you don't have browser, you can download it from ##### If you don't have browser, you can download it from
[Google Chrome](https://www.google.com/intl/en_pk/chrome/) or [Opera](https://www.opera.com/download) or [Edge](https://www.microsoft.com/en-us/edge) or [Firefox](https://www.mozilla.org/en-US/firefox/new/) or [Brave](https://www.brave.com/download/)
##### 如果沒有瀏覽器,可以從 ##### 如果沒有瀏覽器,可以從这里下載
[Google Chrome](https://www.google.com/intl/en_pk/chrome/) 或 [Opera](https://www.opera.com/download) 或 [Edge](https://www.microsoft.com/en-us/edge) 或 [Firefox](https://www.mozilla.org/en-US/firefox/new/) 或 [Brave](https://www.brave.com/download/) 下載
[Google Chrome](https://www.google.com/intl/en_pk/chrome/) | [Opera](https://www.opera.com/download) | [Edge](https://www.microsoft.com/en-us/edge) | [Firefox](https://www.mozilla.org/en-US/firefox/new/) | [Brave](https://www.brave.com/download/)
</div> </div>
@@ -71,11 +71,11 @@ Always clean your browser's cache and cookies. If possible, use a VPN to create
## 💻 System Support | 系統支持 ## 💻 System Support | 系統支持
| Windows | x64 | ✅ | macOS | Intel | ✅ | | Operating System | Architecture | Supported |
|:-------:|:-----:|:-:|:-----:|:-------------:|:-:| |------------------|-------------------|-----------|
| Windows | x86 | ✅ | macOS | Apple Silicon | ✅ | | Windows | x64, x86 | ✅ |
| Linux | x64 | ✅ | Linux | x86 | ✅ | | macOS | Intel, Apple Silicon | ✅ |
| Linux | ARM64 | ✅ | Linux | ARM64 | ✅ | | Linux | x64, x86, ARM64 | ✅ |
## 👀 How to use | 如何使用 ## 👀 How to use | 如何使用

View File

@@ -79,7 +79,7 @@ class CursorRegistration:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_email') if self.translator else '无效的邮箱地址'}{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_email') if self.translator else '无效的邮箱地址'}{Style.RESET_ALL}")
return False return False
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('register.email_address')}: {self.email_address}\n{Style.RESET_ALL}") print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('register.email_address')}: {self.email_address}" + "\n" + f"{Style.RESET_ALL}")
return True return True
except Exception as e: except Exception as e:

View File

@@ -247,11 +247,11 @@ class CursorGoogleAccountDeleter(OAuthHandler):
except: except:
# Try direct JavaScript input as fallback # Try direct JavaScript input as fallback
try: try:
self.browser.run_js(f""" self.browser.run_js(r"""
arguments[0].value = "Delete"; arguments[0].value = "Delete";
const event = new Event('input', {{ bubbles: true }}); const event = new Event('input', { bubbles: true });
arguments[0].dispatchEvent(event); arguments[0].dispatchEvent(event);
const changeEvent = new Event('change', {{ bubbles: true }}); const changeEvent = new Event('change', { bubbles: true });
arguments[0].dispatchEvent(changeEvent); arguments[0].dispatchEvent(changeEvent);
""", delete_input) """, delete_input)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('account_delete.typed_delete_js', fallback='Typed \"Delete\" using JavaScript')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('account_delete.typed_delete_js', fallback='Typed \"Delete\" using JavaScript')}{Style.RESET_ALL}")

284
main.py
View File

@@ -110,18 +110,24 @@ class Translator:
threadid = user32.GetWindowThreadProcessId(hwnd, 0) threadid = user32.GetWindowThreadProcessId(hwnd, 0)
layout_id = user32.GetKeyboardLayout(threadid) & 0xFFFF layout_id = user32.GetKeyboardLayout(threadid) & 0xFFFF
# Map language ID to our language codes # Map language ID to our language codes using match-case
language_map = { match layout_id:
0x0409: 'en', # English case 0x0409:
0x0404: 'zh_tw', # Traditional Chinese return 'en' # English
0x0804: 'zh_cn', # Simplified Chinese case 0x0404:
0x0422: 'vi', # Vietnamese return 'zh_tw' # Traditional Chinese
0x0419: 'ru', # Russian case 0x0804:
0x0415: 'tr', # Turkish return 'zh_cn' # Simplified Chinese
0x0402: 'bg', # Bulgarian case 0x0422:
} return 'vi' # Vietnamese
case 0x0419:
return language_map.get(layout_id, 'en') return 'ru' # Russian
case 0x0415:
return 'tr' # Turkish
case 0x0402:
return 'bg' # Bulgarian
case _:
return 'en' # Default to English
except: except:
return self._detect_unix_language() return self._detect_unix_language()
@@ -136,53 +142,56 @@ class Translator:
system_locale = system_locale.lower() system_locale = system_locale.lower()
# Map locale to our language codes # Map locale to our language codes using match-case
if system_locale.startswith('zh_tw') or system_locale.startswith('zh_hk'): match system_locale:
return 'zh_tw' case s if s.startswith('zh_tw') or s.startswith('zh_hk'):
elif system_locale.startswith('zh_cn'): return 'zh_tw'
return 'zh_cn' case s if s.startswith('zh_cn'):
elif system_locale.startswith('en'): return 'zh_cn'
return 'en' case s if s.startswith('en'):
elif system_locale.startswith('vi'): return 'en'
return 'vi' case s if s.startswith('vi'):
elif system_locale.startswith('nl'): return 'vi'
return 'nl' case s if s.startswith('nl'):
elif system_locale.startswith('de'): return 'nl'
return 'de' case s if s.startswith('de'):
elif system_locale.startswith('fr'): return 'de'
return 'fr' case s if s.startswith('fr'):
elif system_locale.startswith('pt'): return 'fr'
return 'pt' case s if s.startswith('pt'):
elif system_locale.startswith('ru'): return 'pt'
return 'ru' case s if s.startswith('ru'):
elif system_locale.startswith('tr'): return 'ru'
return 'tr' case s if s.startswith('tr'):
elif system_locale.startswith('bg'): return 'tr'
return 'bg' case s if s.startswith('bg'):
# Try to get language from LANG environment variable as fallback return 'bg'
env_lang = os.getenv('LANG', '').lower() case _:
if 'tw' in env_lang or 'hk' in env_lang: # Try to get language from LANG environment variable as fallback
return 'zh_tw' env_lang = os.getenv('LANG', '').lower()
elif 'cn' in env_lang: match env_lang:
return 'zh_cn' case s if 'tw' in s or 'hk' in s:
elif 'vi' in env_lang: return 'zh_tw'
return 'vi' case s if 'cn' in s:
elif 'nl' in env_lang: return 'zh_cn'
return 'nl' case s if 'vi' in s:
elif 'de' in env_lang: return 'vi'
return 'de' case s if 'nl' in s:
elif 'fr' in env_lang: return 'nl'
return 'fr' case s if 'de' in s:
elif 'pt' in env_lang: return 'de'
return 'pt' case s if 'fr' in s:
elif 'ru' in env_lang: return 'fr'
return 'ru' case s if 'pt' in s:
elif 'tr' in env_lang: return 'pt'
return 'tr' case s if 'ru' in s:
elif 'bg' in env_lang: return 'ru'
return 'bg' case s if 'tr' in s:
return 'tr'
return 'en' case s if 'bg' in s:
return 'bg'
case _:
return 'en'
except: except:
return 'en' return 'en'
@@ -566,87 +575,88 @@ def main():
choice_num = 17 choice_num = 17
choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices=f'0-{choice_num}')}: {Style.RESET_ALL}") choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices=f'0-{choice_num}')}: {Style.RESET_ALL}")
if choice == "0": match choice:
print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.exit')}...{Style.RESET_ALL}") case "0":
print(f"{Fore.CYAN}{'' * 50}{Style.RESET_ALL}") print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.exit')}...{Style.RESET_ALL}")
return print(f"{Fore.CYAN}{'' * 50}{Style.RESET_ALL}")
elif choice == "1": return
import reset_machine_manual case "1":
reset_machine_manual.run(translator) import reset_machine_manual
print_menu() reset_machine_manual.run(translator)
elif choice == "2": print_menu()
import cursor_register case "2":
cursor_register.main(translator) import cursor_register
print_menu() cursor_register.main(translator)
elif choice == "3": print_menu()
import cursor_register_google case "3":
cursor_register_google.main(translator) import cursor_register_google
print_menu() cursor_register_google.main(translator)
elif choice == "4": print_menu()
import cursor_register_github case "4":
cursor_register_github.main(translator) import cursor_register_github
print_menu() cursor_register_github.main(translator)
elif choice == "5": print_menu()
import cursor_register_manual case "5":
cursor_register_manual.main(translator) import cursor_register_manual
print_menu() cursor_register_manual.main(translator)
elif choice == "6": print_menu()
import github_cursor_register case "6":
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.coming_soon')}{Style.RESET_ALL}") import github_cursor_register
# github_cursor_register.main(translator) print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.coming_soon')}{Style.RESET_ALL}")
print_menu() # github_cursor_register.main(translator)
elif choice == "7": print_menu()
import quit_cursor case "7":
quit_cursor.quit_cursor(translator) import quit_cursor
print_menu() quit_cursor.quit_cursor(translator)
elif choice == "8": print_menu()
if select_language(): case "8":
if select_language():
print_menu()
continue
case "9":
import disable_auto_update
disable_auto_update.run(translator)
print_menu()
case "10":
import totally_reset_cursor
totally_reset_cursor.run(translator)
# print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.fixed_soon')}{Style.RESET_ALL}")
print_menu()
case "11":
import logo
print(logo.CURSOR_CONTRIBUTORS)
print_menu()
case "12":
from config import print_config
print_config(get_config(), translator)
print_menu()
case "13":
from oauth_auth import OAuthHandler
oauth = OAuthHandler(translator)
oauth._select_profile()
print_menu()
case "14":
import delete_cursor_google
delete_cursor_google.main(translator)
print_menu()
case "15":
import bypass_version
bypass_version.main(translator)
print_menu()
case "16":
import check_user_authorized
check_user_authorized.main(translator)
print_menu()
case "17":
import bypass_token_limit
bypass_token_limit.run(translator)
print_menu()
case _:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
print_menu() print_menu()
continue
elif choice == "9":
import disable_auto_update
disable_auto_update.run(translator)
print_menu()
elif choice == "10":
import totally_reset_cursor
totally_reset_cursor.run(translator)
# print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.fixed_soon')}{Style.RESET_ALL}")
print_menu()
elif choice == "11":
import logo
print(logo.CURSOR_CONTRIBUTORS)
print_menu()
elif choice == "12":
from config import print_config
print_config(get_config(), translator)
print_menu()
elif choice == "13":
from oauth_auth import OAuthHandler
oauth = OAuthHandler(translator)
oauth._select_profile()
print_menu()
elif choice == "14":
import delete_cursor_google
delete_cursor_google.main(translator)
print_menu()
elif choice == "15":
import bypass_version
bypass_version.main(translator)
print_menu()
elif choice == "16":
import check_user_authorized
check_user_authorized.main(translator)
print_menu()
elif choice == "17":
import bypass_token_limit
bypass_token_limit.run(translator)
print_menu()
else:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
print_menu()
except KeyboardInterrupt: except KeyboardInterrupt:
print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.program_terminated')}{Style.RESET_ALL}") print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.program_terminated')}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{'' * 50}{Style.RESET_ALL}") print(f"{Fore.CYAN}{'' * 50}{Style.RESET_ALL}")
return return
except Exception as e: except Exception as e:

View File

@@ -139,7 +139,7 @@ class NewTempEmail:
if sys.platform == "linux": if sys.platform == "linux":
# Check if DISPLAY is set when not in headless mode # Check if DISPLAY is set when not in headless mode
if not co.arguments.get("--headless=new") and not os.environ.get('DISPLAY'): if "--headless=new" not in co.arguments and not os.environ.get('DISPLAY'):
print(f"{Fore.RED}{self.translator.get('email.no_display_found') if self.translator else 'No display found. Make sure X server is running.'}{Style.RESET_ALL}") print(f"{Fore.RED}{self.translator.get('email.no_display_found') if self.translator else 'No display found. Make sure X server is running.'}{Style.RESET_ALL}")
print(f"{Fore.YELLOW} {self.translator.get('email.try_export_display') if self.translator else 'Try: export DISPLAY=:0'}{Style.RESET_ALL}") print(f"{Fore.YELLOW} {self.translator.get('email.try_export_display') if self.translator else 'Try: export DISPLAY=:0'}{Style.RESET_ALL}")
return False return False

View File

@@ -1,3 +1,4 @@
# oauth_auth.py
import os import os
from colorama import Fore, Style, init from colorama import Fore, Style, init
import time import time
@@ -30,7 +31,7 @@ class OAuthHandler:
def __init__(self, translator=None, auth_type=None): def __init__(self, translator=None, auth_type=None):
self.translator = translator self.translator = translator
self.config = get_config(translator) self.config = get_config(translator)
self.auth_type = auth_type # make sure the auth_type is not None self.auth_type = auth_type
os.environ['BROWSER_HEADLESS'] = 'False' os.environ['BROWSER_HEADLESS'] = 'False'
self.browser = None self.browser = None
self.selected_profile = None self.selected_profile = None
@@ -176,10 +177,15 @@ class OAuthHandler:
browser_path = self._get_browser_path() browser_path = self._get_browser_path()
if not browser_path: if not browser_path:
raise Exception(f"{self.translator.get('oauth.no_compatible_browser_found') if self.translator else 'No compatible browser found. Please install Google Chrome or Chromium.'}\n{self.translator.get('oauth.supported_browsers', platform=platform_name)}\n" + error_msg = (
"- Windows: Google Chrome, Chromium\n" + f"{self.translator.get('oauth.no_compatible_browser_found') if self.translator else 'No compatible browser found. Please install Google Chrome or Chromium.'}" +
"- macOS: Google Chrome, Chromium\n" + "\n" +
"- Linux: Google Chrome, Chromium, chromium-browser") f"{self.translator.get('oauth.supported_browsers', platform=platform_name)}\n" +
"- Windows: Google Chrome, Chromium\n" +
"- macOS: Google Chrome, Chromium\n" +
"- Linux: Google Chrome, Chromium, google-chrome-stable"
)
raise Exception(error_msg)
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_browser_data_directory', path=user_data_dir) if self.translator else f'Found browser data directory: {user_data_dir}'}{Style.RESET_ALL}") print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_browser_data_directory', path=user_data_dir) if self.translator else f'Found browser data directory: {user_data_dir}'}{Style.RESET_ALL}")
@@ -239,7 +245,7 @@ class OAuthHandler:
browser_processes = { browser_processes = {
'chrome': { 'chrome': {
'win': ['chrome.exe', 'chromium.exe'], 'win': ['chrome.exe', 'chromium.exe'],
'linux': ['chrome', 'chromium', 'chromium-browser'], 'linux': ['chrome', 'chromium', 'chromium-browser', 'google-chrome-stable'],
'mac': ['Chrome', 'Chromium'] 'mac': ['Chrome', 'Chromium']
}, },
'brave': { 'brave': {
@@ -423,7 +429,12 @@ class OAuthHandler:
elif browser_type == 'firefox': elif browser_type == 'firefox':
possible_paths = ['/usr/bin/firefox'] possible_paths = ['/usr/bin/firefox']
else: # 默认为 Chrome else: # 默认为 Chrome
possible_paths = ['/usr/bin/google-chrome', '/usr/bin/google-chrome-stable', '/usr/bin/chromium', '/usr/bin/chromium-browser'] possible_paths = [
'/usr/bin/google-chrome-stable', # 优先检查 google-chrome-stable
'/usr/bin/google-chrome',
'/usr/bin/chromium',
'/usr/bin/chromium-browser'
]
# 检查每个可能的路径 # 检查每个可能的路径
for path in possible_paths: for path in possible_paths:
@@ -431,7 +442,7 @@ class OAuthHandler:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.found_browser_at', path=path) if self.translator else f'Found browser at: {path}'}{Style.RESET_ALL}") print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.found_browser_at', path=path) if self.translator else f'Found browser at: {path}'}{Style.RESET_ALL}")
return path return path
# 如果找不到指定浏览器则尝试使用Chrome # 如果找不到指定浏览器,则尝试使用 Chrome
if browser_type != 'chrome': if browser_type != 'chrome':
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('oauth.browser_not_found_trying_chrome', browser=browser_type) if self.translator else f'Could not find {browser_type}, trying Chrome instead'}{Style.RESET_ALL}") print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('oauth.browser_not_found_trying_chrome', browser=browser_type) if self.translator else f'Could not find {browser_type}, trying Chrome instead'}{Style.RESET_ALL}")
return self._get_chrome_path() return self._get_chrome_path()
@@ -442,29 +453,6 @@ class OAuthHandler:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_finding_browser_path', error=str(e)) if self.translator else f'Error finding browser path: {e}'}{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_finding_browser_path', error=str(e)) if self.translator else f'Error finding browser path: {e}'}{Style.RESET_ALL}")
return None return None
def _get_chrome_path(self):
"""Fallback method to get Chrome path"""
try:
if os.name == 'nt': # Windows
possible_paths = [
os.path.join(os.environ.get('PROGRAMFILES', ''), 'Google', 'Chrome', 'Application', 'chrome.exe'),
os.path.join(os.environ.get('PROGRAMFILES(X86)', ''), 'Google', 'Chrome', 'Application', 'chrome.exe'),
os.path.join(os.environ.get('LOCALAPPDATA', ''), 'Google', 'Chrome', 'Application', 'chrome.exe')
]
elif sys.platform == 'darwin': # macOS
possible_paths = ['/Applications/Google Chrome.app/Contents/MacOS/Google Chrome']
else: # Linux
possible_paths = ['/usr/bin/google-chrome', '/usr/bin/google-chrome-stable', '/usr/bin/chromium', '/usr/bin/chromium-browser']
for path in possible_paths:
if os.path.exists(path):
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.found_chrome_at', path=path) if self.translator else f'Found Chrome at: {path}'}{Style.RESET_ALL}")
return path
return None
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_finding_chrome_path', error=str(e)) if self.translator else f'Error finding Chrome path: {e}'}{Style.RESET_ALL}")
return None
def _configure_browser_options(self, browser_path, user_data_dir, active_profile): def _configure_browser_options(self, browser_path, user_data_dir, active_profile):
"""Configure browser options based on platform""" """Configure browser options based on platform"""
try: try:
@@ -476,6 +464,7 @@ class OAuthHandler:
co.set_argument('--no-first-run') co.set_argument('--no-first-run')
co.set_argument('--no-default-browser-check') co.set_argument('--no-default-browser-check')
co.set_argument('--disable-gpu') co.set_argument('--disable-gpu')
co.set_argument('--remote-debugging-port=9222') # 明确指定调试端口
# Platform-specific options # Platform-specific options
if sys.platform.startswith('linux'): if sys.platform.startswith('linux'):
@@ -958,7 +947,8 @@ class OAuthHandler:
value = cookie.get("value", "") value = cookie.get("value", "")
token = get_token_from_cookie(value, self.translator) token = get_token_from_cookie(value, self.translator)
except Exception as e: except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.token_extraction_error', error=str(e)) if self.translator else f'Token extraction error: {str(e)}'}{Style.RESET_ALL}") error_message = f'Failed to extract auth info: {str(e)}' if not self.translator else self.translator.get('oauth.failed_to_extract_auth_info', error=str(e))
print(f"{Fore.RED}{EMOJI['ERROR']} {error_message}{Style.RESET_ALL}")
elif name == "cursor_email": elif name == "cursor_email":
email = cookie.get("value") email = cookie.get("value")
@@ -971,11 +961,13 @@ class OAuthHandler:
missing.append("email") missing.append("email")
if not token: if not token:
missing.append("token") missing.append("token")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.missing_authentication_data', data=', '.join(missing)) if self.translator else f'Missing authentication data: {", ".join(missing)}'}{Style.RESET_ALL}") error_message = f"Missing authentication data: {', '.join(missing)}" if not self.translator else self.translator.get('oauth.missing_authentication_data', data=', '.join(missing))
print(f"{Fore.RED}{EMOJI['ERROR']} {error_message}{Style.RESET_ALL}")
return False, None return False, None
except Exception as e: except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_extract_auth_info', error=str(e)) if self.translator else f'Failed to extract auth info: {str(e)}'}{Style.RESET_ALL}") error_message = f'Failed to extract auth info: {str(e)}' if not self.translator else self.translator.get('oauth.failed_to_extract_auth_info', error=str(e))
print(f"{Fore.RED}{EMOJI['ERROR']} {error_message}{Style.RESET_ALL}")
return False, None return False, None
def _delete_current_account(self): def _delete_current_account(self):
@@ -1017,7 +1009,8 @@ class OAuthHandler:
return True return True
except Exception as e: except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_delete_account', error=str(e)) if self.translator else f'Failed to delete account: {str(e)}'}{Style.RESET_ALL}") error_message = f'Failed to delete account: {str(e)}' if not self.translator else self.translator.get('oauth.failed_to_delete_account', error=str(e))
print(f"{Fore.RED}{EMOJI['ERROR']} {error_message}{Style.RESET_ALL}")
return False return False
def main(auth_type, translator=None): def main(auth_type, translator=None):