Compare commits

...

21 Commits

Author SHA1 Message Date
Pin Studios
1c36ff010e
Merge pull request #1033 from LoveDoLove/lovedolove
修復 install.ps1 下載狀態條的問題
2025-06-18 10:18:31 +08:00
LoveDoLove
4f060abc93 修復 progress bar 下載狀態不對稱 install.ps1 2025-06-13 10:51:29 +08:00
yeongpin
e8ab5654ad Map Source Code 2025-05-22 10:41:36 +08:00
Pin Studios
f9e3c6025b
Merge pull request #893 from cjahv/main
增强TempMailPlusTab类,添加轮询功能以检查新邮件,支持自定义轮询间隔和最大尝试次数
2025-05-21 10:29:17 +08:00
jahv
d02e5d69c8 增强TempMailPlusTab类,添加轮询功能以检查新邮件,支持自定义轮询间隔和最大尝试次数。同时更新文档以反映新参数,并优化了部分注释的翻译。 2025-05-15 00:30:09 +08:00
Pin Studios
849de8fac2
Merge pull request #836 from cjahv/main
新增 AccountManager 类,支持推荐邮箱及账户信息统一保存
2025-05-12 11:31:22 +08:00
cjahv
201557d79c
Merge branch 'yeongpin:main' into main 2025-05-06 15:53:23 +08:00
yeongpin
30418e36a5 Update version to 1.11.03 and document changes in CHANGELOG.md, including improvements to TempMailPlus email detection logic and fixes for Windows user directory path issues. 2025-05-06 13:33:40 +08:00
jahv
c3a3963a76 Merge branch 'main' of github.com:cjahv/cursor-free-vip 2025-05-02 14:02:01 +08:00
Pin Studios
baec0937c3
Merge pull request #832 from AmzGrainRain/main
修正 windows 环境下用户目录的获取方式
2025-05-02 12:13:57 +08:00
Pin Studios
bdbec76a7b
Merge pull request #829 from cjahv/main
在 README.md 中新增 TempMailPlus 配置项说明
2025-05-02 12:13:03 +08:00
AmzGrainRain
3386d8e08e 修正 windows 环境下用户目录的获取方式 2025-05-01 14:37:36 +08:00
jahv
cb9ec64388 新增账户管理类,创建AccountManager类以处理账户信息的保存和建议邮箱的生成。同时更新CursorRegistration类以使用AccountManager进行账户信息的保存,并在用户输入邮箱时提供建议邮箱功能。更新多语言本地化文件以支持新功能的翻译。 2025-05-01 13:25:16 +08:00
jahv
76179807bc 在README.md中新增TempMailPlus配置选项,包含启用状态、电子邮件地址和PIN码设置,以支持邮件验证功能的扩展。 2025-04-30 23:12:12 +08:00
Pin Studios
f8499708c9
Merge pull request #823 from cjahv/main
🚀 更新 TempMailPlus 的 Cursor 邮件识别逻辑
2025-04-30 17:10:20 +08:00
Pin Studios
4a459574ad Enhance TempMailPlus integration by adding translator support for internationalization, improving error messages, and updating the email tab interface documentation. Additionally, update localization files for multiple languages to include new translation keys related to email verification processes. 2025-04-30 17:09:53 +08:00
jahv
2d1604c646 增强邮件验证功能,新增发件人邮箱检查,确保发件人包含'cursor'字符串以提高邮件处理的准确性。 2025-04-30 07:56:28 +08:00
jahv
be950c510c 增强邮件检查功能,新增验证码缓存机制,优化获取验证码的方法,并更新相关文档注释。 2025-04-30 07:49:54 +08:00
jahv
e190a81ee4 优化邮件检查功能,简化逻辑,直接检查邮件列表中的第一个邮件是否为新邮件,并更新相关文档注释。 2025-04-30 07:41:12 +08:00
cjahv
fa74b17dce
Merge branch 'yeongpin:main' into main 2025-04-29 10:17:23 +08:00
jahv
db490718c5 更新邮件检查功能,支持检查最近3分钟内的邮件,并更新错误处理信息。同时,添加了主程序入口以便于直接运行和测试TempMailPlusTab类。 2025-04-29 10:07:02 +08:00
30 changed files with 1031440 additions and 109 deletions

4
.env
View File

@ -1,2 +1,2 @@
version=1.11.02 version=1.11.03
VERSION=1.11.02 VERSION=1.11.03

View File

@ -1,5 +1,10 @@
# Change Log # Change Log
## v1.11.03
1. Update: TempMailPlus Cursor Email Detection Logic | 更新 TempMailPlus Cursor 邮件识别逻辑
2. Fix: Windows User Directory Path | 修正 windows 环境下用户目录的获取方式
3. Fix: Some Issues | 修復一些問題
## v1.11.02 ## v1.11.02
1. Fill: Missing Translationsar, zh-cn, zh-tw, vi, nl, de, fr, pt, ru, tr, bg, es, ja, it | 填補缺失的翻譯 1. Fill: Missing Translationsar, zh-cn, zh-tw, vi, nl, de, fr, pt, ru, tr, bg, es, ja, it | 填補缺失的翻譯
2. Add: Japanese and Italian language support 2. Add: Japanese and Italian language support

View File

@ -159,6 +159,14 @@ check_update = True
# Show Account Info | 顯示賬號信息 # Show Account Info | 顯示賬號信息
show_account_info = True show_account_info = True
[TempMailPlus]
# Enable TempMailPlus | 啓用 TempMailPlus任何轉發到TempMailPlus的郵件都支持獲取驗證碼例如cloudflare郵件Catch-all
enabled = false
# TempMailPlus Email | TempMailPlus 電子郵件
email = xxxxx@mailto.plus
# TempMailPlus pin | TempMailPlus pin碼
epin =
[WindowsPaths] [WindowsPaths]
storage_path = C:\Users\yeongpin\AppData\Roaming\Cursor\User\globalStorage\storage.json storage_path = C:\Users\yeongpin\AppData\Roaming\Cursor\User\globalStorage\storage.json
sqlite_path = C:\Users\yeongpin\AppData\Roaming\Cursor\User\globalStorage\state.vscdb sqlite_path = C:\Users\yeongpin\AppData\Roaming\Cursor\User\globalStorage\state.vscdb

97
account_manager.py Normal file
View File

@ -0,0 +1,97 @@
import os
from colorama import Fore, Style
import re
# Define emoji constants
EMOJI = {
'SUCCESS': '',
'ERROR': '',
'INFO': ''
}
class AccountManager:
def __init__(self, translator=None):
self.translator = translator
self.accounts_file = 'cursor_accounts.txt'
def save_account_info(self, email, password, token, total_usage):
"""Save account information to file"""
try:
with open(self.accounts_file, 'a', encoding='utf-8') as f:
f.write(f"\n{'='*50}\n")
f.write(f"Email: {email}\n")
f.write(f"Password: {password}\n")
f.write(f"Token: {token}\n")
f.write(f"Usage Limit: {total_usage}\n")
f.write(f"{'='*50}\n")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.account_info_saved') if self.translator else 'Account information saved'}...{Style.RESET_ALL}")
return True
except Exception as e:
error_msg = self.translator.get('register.save_account_info_failed', error=str(e)) if self.translator else f'Failed to save account information: {str(e)}'
print(f"{Fore.RED}{EMOJI['ERROR']} {error_msg}{Style.RESET_ALL}")
return False
def get_last_email_domain(self):
"""Get the domain from the last used email"""
try:
if not os.path.exists(self.accounts_file):
return None
# Only read the last 1KB of data from the file
with open(self.accounts_file, 'rb') as f:
# Get file size
f.seek(0, os.SEEK_END)
file_size = f.tell()
if file_size == 0:
return None
# Determine the number of bytes to read, maximum 1KB
read_size = min(1024, file_size)
# Move to the appropriate position to start reading
f.seek(file_size - read_size)
# Read the end data
data = f.read(read_size).decode('utf-8', errors='ignore')
# Split by lines and search in reverse
lines = data.split('\n')
for line in reversed(lines):
if line.strip().startswith('Email:'):
email = line.split('Email:')[1].strip()
# Extract domain part (after @)
if '@' in email:
return email.split('@')[1]
return None
# If no email is found in the last 1KB
return None
except Exception as e:
error_msg = self.translator.get('account.get_last_email_domain_failed', error=str(e)) if self.translator else f'Failed to get the last used email domain: {str(e)}'
print(f"{Fore.RED}{EMOJI['ERROR']} {error_msg}{Style.RESET_ALL}")
return None
def suggest_email(self, first_name, last_name):
"""Generate a suggested email based on first and last name with the last used domain"""
try:
# Get the last used email domain
domain = self.get_last_email_domain()
if not domain:
return None
# Generate email prefix from first and last name (lowercase)
email_prefix = f"{first_name.lower()}.{last_name.lower()}"
# Combine prefix and domain
suggested_email = f"{email_prefix}@{domain}"
return suggested_email
except Exception as e:
error_msg = self.translator.get('account.suggest_email_failed', error=str(e)) if self.translator else f'Failed to suggest email: {str(e)}'
print(f"{Fore.RED}{EMOJI['ERROR']} {error_msg}{Style.RESET_ALL}")
return None

View File

@ -26,7 +26,14 @@ EMOJI = {
def get_user_documents_path(): def get_user_documents_path():
"""Get user Documents folder path""" """Get user Documents folder path"""
if sys.platform == "win32": if sys.platform == "win32":
return os.path.join(os.path.expanduser("~"), "Documents") try:
import winreg
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") as key:
documents_path, _ = winreg.QueryValueEx(key, "Personal")
return documents_path
except Exception as e:
# fallback
return os.path.join(os.path.expanduser("~"), "Documents")
elif sys.platform == "darwin": elif sys.platform == "darwin":
return os.path.join(os.path.expanduser("~"), "Documents") return os.path.join(os.path.expanduser("~"), "Documents")
else: # Linux else: # Linux

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -7,6 +7,7 @@ from cursor_auth import CursorAuth
from reset_machine_manual import MachineIDResetter from reset_machine_manual import MachineIDResetter
from get_user_token import get_token_from_cookie from get_user_token import get_token_from_cookie
from config import get_config from config import get_config
from account_manager import AccountManager
os.environ["PYTHONVERBOSE"] = "0" os.environ["PYTHONVERBOSE"] = "0"
os.environ["PYINSTALLER_VERBOSE"] = "0" os.environ["PYINSTALLER_VERBOSE"] = "0"
@ -67,11 +68,28 @@ class CursorRegistration:
def setup_email(self): def setup_email(self):
"""Setup Email""" """Setup Email"""
try: try:
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.manual_email_input') if self.translator else 'Please enter your email address:'}") # Try to get a suggested email
self.email_address = input().strip() account_manager = AccountManager(self.translator)
suggested_email = account_manager.suggest_email(self.first_name, self.last_name)
if suggested_email:
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.suggest_email', suggested_email=suggested_email) if self.translator else f'Suggested email: {suggested_email}'}")
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.use_suggested_email_or_enter') if self.translator else 'Type "yes" to use this email or enter your own email:'}")
user_input = input().strip()
if user_input.lower() == 'yes' or user_input.lower() == 'y':
self.email_address = suggested_email
else:
# User input is their own email address
self.email_address = user_input
else:
# If there's no suggested email
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()
# Validate if the email is valid
if '@' not in self.email_address: 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}") print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_email') if self.translator else 'Invalid email address'}{Style.RESET_ALL}")
return False return False
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('register.email_address')}: {self.email_address}" + "\n" + f"{Style.RESET_ALL}") print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('register.email_address')}: {self.email_address}" + "\n" + f"{Style.RESET_ALL}")
@ -88,7 +106,7 @@ class CursorRegistration:
code = input().strip() code = input().strip()
if not code.isdigit() or len(code) != 6: if not code.isdigit() or len(code) != 6:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_code') if self.translator else '无效的验证码'}{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_code') if self.translator else 'Invalid verification code'}{Style.RESET_ALL}")
return None return None
return code return code
@ -112,7 +130,7 @@ class CursorRegistration:
epin = config.get('TempMailPlus', 'epin') epin = config.get('TempMailPlus', 'epin')
if email and epin: if email and epin:
from email_tabs.tempmail_plus_tab import TempMailPlusTab from email_tabs.tempmail_plus_tab import TempMailPlusTab
email_tab = TempMailPlusTab(email, epin) email_tab = TempMailPlusTab(email, epin, self.translator)
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('register.using_tempmail_plus')}{Style.RESET_ALL}") print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('register.using_tempmail_plus')}{Style.RESET_ALL}")
# Use new_signup.py directly for registration # Use new_signup.py directly for registration
@ -224,17 +242,12 @@ class CursorRegistration:
if not resetter.reset_machine_ids(): # Call reset_machine_ids method directly if not resetter.reset_machine_ids(): # Call reset_machine_ids method directly
raise Exception("Failed to reset machine ID") raise Exception("Failed to reset machine ID")
# Save account information to file # Save account information to file using AccountManager
with open('cursor_accounts.txt', 'a', encoding='utf-8') as f: account_manager = AccountManager(self.translator)
f.write(f"\n{'='*50}\n") if account_manager.save_account_info(self.email_address, self.password, token, total_usage):
f.write(f"Email: {self.email_address}\n") return True
f.write(f"Password: {self.password}\n") else:
f.write(f"Token: {token}\n") return False
f.write(f"Usage Limit: {total_usage}\n")
f.write(f"{'='*50}\n")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.account_info_saved')}...{Style.RESET_ALL}")
return True
except Exception as e: except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.save_account_info_failed', error=str(e))}{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.save_account_info_failed', error=str(e))}{Style.RESET_ALL}")

View File

@ -1,7 +1,7 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
class EmailTabInterface(ABC): class EmailTabInterface(ABC):
"""Email tab interface for handling email verification""" """Interface for email tab implementations"""
@abstractmethod @abstractmethod
def refresh_inbox(self) -> None: def refresh_inbox(self) -> None:
@ -10,10 +10,10 @@ class EmailTabInterface(ABC):
@abstractmethod @abstractmethod
def check_for_cursor_email(self) -> bool: def check_for_cursor_email(self) -> bool:
"""Check if there is a verification email from Cursor """Check if there is a new email from Cursor
Returns: Returns:
bool: True if verification email exists, False otherwise bool: True if new email found, False otherwise
""" """
pass pass
@ -22,6 +22,6 @@ class EmailTabInterface(ABC):
"""Get the verification code from the email """Get the verification code from the email
Returns: Returns:
str: The verification code if found, empty string otherwise str: The verification code if available, empty string otherwise
""" """
pass pass

View File

@ -1,20 +1,27 @@
import requests import requests
import re import re
import datetime
import time
from typing import Optional from typing import Optional
from .email_tab_interface import EmailTabInterface from .email_tab_interface import EmailTabInterface
class TempMailPlusTab(EmailTabInterface): class TempMailPlusTab(EmailTabInterface):
"""Implementation of EmailTabInterface for tempmail.plus""" """Implementation of EmailTabInterface for tempmail.plus"""
def __init__(self, email: str, epin: str): def __init__(self, email: str, epin: str, translator=None,
polling_interval: int = 2, max_attempts: int = 10):
"""Initialize TempMailPlusTab """Initialize TempMailPlusTab
Args: Args:
email: The email address to check email: The email address to check
epin: The epin token for authentication epin: The epin token for authentication
translator: Optional translator for internationalization
polling_interval: Time in seconds between polling attempts
max_attempts: Maximum number of polling attempts
""" """
self.email = email self.email = email
self.epin = epin self.epin = epin
self.translator = translator
self.base_url = "https://tempmail.plus/api" self.base_url = "https://tempmail.plus/api"
self.headers = { self.headers = {
'accept': 'application/json', 'accept': 'application/json',
@ -32,17 +39,59 @@ class TempMailPlusTab(EmailTabInterface):
'x-requested-with': 'XMLHttpRequest' 'x-requested-with': 'XMLHttpRequest'
} }
self.cookies = {'email': email} self.cookies = {'email': email}
self._cached_mail_id = None # 缓存mail_id self._cached_mail_id = None # Cache for mail_id
self._cached_verification_code = None # Cache for verification code
# Polling configuration
self.polling_interval = polling_interval
self.max_attempts = max_attempts
self.current_attempt = 0
def refresh_inbox(self) -> None: def refresh_inbox(self) -> None:
"""Refresh the email inbox""" """Refresh the email inbox"""
pass pass
def check_for_cursor_email(self) -> bool: def check_for_cursor_email(self) -> bool:
"""Check if there is a verification email from Cursor """Check if there is a new email and immediately retrieve verification code
Returns: Returns:
bool: True if verification email exists, False otherwise bool: True if new email found and verification code retrieved, False otherwise
"""
# Reset attempt counter
self.current_attempt = 0
# Polling logic
while self.current_attempt < self.max_attempts:
found = self._check_email_once()
if found:
# Successfully found email and retrieved verification code
self.current_attempt = 0 # Reset counter for next use
return True
# Not found, continue polling
self.current_attempt += 1
if self.current_attempt < self.max_attempts:
# Print polling status information
if self.translator:
print(self.translator.get('tempmail.polling',
attempt=self.current_attempt,
max=self.max_attempts))
else:
print(f"Polling for email: attempt {self.current_attempt}/{self.max_attempts}")
time.sleep(self.polling_interval)
# Exceeded maximum attempts
if self.translator:
print(self.translator.get('tempmail.max_attempts_reached'))
else:
print(f"Max attempts ({self.max_attempts}) reached. No verification email found.")
return False
def _check_email_once(self) -> bool:
"""Single attempt to check for email
Returns:
bool: True if new email found and verification code retrieved, False otherwise
""" """
try: try:
params = { params = {
@ -59,28 +108,30 @@ class TempMailPlusTab(EmailTabInterface):
data = response.json() data = response.json()
if data.get('result') and data.get('mail_list'): if data.get('result') and data.get('mail_list'):
for mail in data['mail_list']: # Check if the first email in the list is a new email
if 'cursor.sh' in mail.get('from_mail', '') and mail.get('is_new') == True: if data['mail_list'][0].get('is_new') == True:
self._cached_mail_id = mail.get('mail_id') # 缓存mail_id self._cached_mail_id = data['mail_list'][0].get('mail_id') # Cache the mail_id
# Immediately retrieve verification code
verification_code = self._extract_verification_code()
if verification_code:
self._cached_verification_code = verification_code
return True return True
return False return False
except Exception as e: except Exception as e:
print(f"检查Cursor邮件失败: {str(e)}") print(f"{self.translator.get('tempmail.check_email_failed', error=str(e)) if self.translator else f'Check email failed: {str(e)}'}")
return False return False
def get_verification_code(self) -> str: def _extract_verification_code(self) -> str:
"""Get the verification code from the email """Extract verification code from email content
Returns: Returns:
str: The verification code if found, empty string otherwise str: The verification code if found, empty string otherwise
""" """
try: try:
# 如果没有缓存的mail_id先检查是否有新邮件
if not self._cached_mail_id: if not self._cached_mail_id:
if not self.check_for_cursor_email(): return ""
return ""
# 使用缓存的mail_id获取邮件内容
params = { params = {
'email': self.email, 'email': self.email,
'epin': self.epin 'epin': self.epin
@ -97,6 +148,11 @@ class TempMailPlusTab(EmailTabInterface):
if not data.get('result'): if not data.get('result'):
return "" return ""
# Verify if sender email contains cursor string
from_mail = data.get('from_mail', '')
if 'cursor' not in from_mail.lower():
return ""
# Extract verification code from text content using regex # Extract verification code from text content using regex
text = data.get('text', '') text = data.get('text', '')
match = re.search(r'\n\n(\d{6})\n\n', text) match = re.search(r'\n\n(\d{6})\n\n', text)
@ -105,5 +161,57 @@ class TempMailPlusTab(EmailTabInterface):
return "" return ""
except Exception as e: except Exception as e:
print(f"获取验证码失败: {str(e)}") print(f"{self.translator.get('tempmail.extract_code_failed', error=str(e)) if self.translator else f'Extract verification code failed: {str(e)}'}")
return "" return ""
def get_verification_code(self) -> str:
"""Get the verification code from cache
Returns:
str: The cached verification code if available, empty string otherwise
"""
return self._cached_verification_code or ""
if __name__ == "__main__":
import os
import sys
import configparser
from config import get_config
# Try to import translator
try:
from main import Translator
translator = Translator()
except ImportError:
translator = None
config = get_config(translator)
try:
email = config.get('TempMailPlus', 'email')
epin = config.get('TempMailPlus', 'epin')
print(f"{translator.get('tempmail.configured_email', email=email) if translator else f'Configured email: {email}'}")
# Initialize TempMailPlusTab, pass translator
mail_tab = TempMailPlusTab(email, epin, translator)
# Check if there is a Cursor email
print(f"{translator.get('tempmail.checking_email') if translator else 'Checking for Cursor verification email...'}")
if mail_tab.check_for_cursor_email():
print(f"{translator.get('tempmail.email_found') if translator else 'Found Cursor verification email'}")
# Get verification code
verification_code = mail_tab.get_verification_code()
if verification_code:
print(f"{translator.get('tempmail.verification_code', code=verification_code) if translator else f'Verification code: {verification_code}'}")
else:
print(f"{translator.get('tempmail.no_code') if translator else 'Could not get verification code'}")
else:
print(f"{translator.get('tempmail.no_email') if translator else 'No Cursor verification email found'}")
except configparser.Error as e:
print(f"{translator.get('tempmail.config_error', error=str(e)) if translator else f'Config file error: {str(e)}'}")
except Exception as e:
print(f"{translator.get('tempmail.general_error', error=str(e)) if translator else f'An error occurred: {str(e)}'}")

View File

@ -850,5 +850,17 @@
"updating_database": "تحديث قاعدة بيانات مصادقة المؤشر ...", "updating_database": "تحديث قاعدة بيانات مصادقة المؤشر ...",
"title": "مصادقة المؤشر اليدوي", "title": "مصادقة المؤشر اليدوي",
"auth_update_failed": "فشل في تحديث معلومات المصادقة" "auth_update_failed": "فشل في تحديث معلومات المصادقة"
},
"tempmail": {
"config_error": "خطأ في ملف التكوين: {error}",
"no_email": "لم يتم العثور على بريد إلكتروني للتحقق من المؤشر",
"general_error": "حدث خطأ: {error}",
"checking_email": "التحقق من البريد الإلكتروني للتحقق من المؤشر ...",
"extract_code_failed": "فشل استخراج رمز التحقق: {error}",
"configured_email": "البريد الإلكتروني المكون: {البريد الإلكتروني}",
"check_email_failed": "فشل التحقق من البريد الإلكتروني: {error}",
"no_code": "لا يمكن الحصول على رمز التحقق",
"email_found": "تم العثور على البريد الإلكتروني للتحقق من المؤشر",
"verification_code": "رمز التحقق: {code}"
} }
} }

View File

@ -863,5 +863,17 @@
"auth_update_failed": "Неуспешно актуализиране на информацията за удостоверяване", "auth_update_failed": "Неуспешно актуализиране на информацията за удостоверяване",
"title": "Ръчно удостоверяване на курсора", "title": "Ръчно удостоверяване на курсора",
"updating_database": "Актуализиране на базата данни за удостоверяване на курсора ..." "updating_database": "Актуализиране на базата данни за удостоверяване на курсора ..."
},
"tempmail": {
"no_email": "Не е намерен имейл за проверка на курсора",
"config_error": "Грешка в конфигурацията на файла: {грешка}",
"general_error": "Възникна грешка: {грешка}",
"configured_email": "Конфигуриран имейл: {имейл}",
"extract_code_failed": "Кодът за проверка на екстракт не успя: {Грешка}",
"checking_email": "Проверка за имейл за проверка на курсора ...",
"no_code": "Не можа да получи код за проверка",
"email_found": "Намерен имейл за проверка на курсора",
"check_email_failed": "Проверете имейла не е успешен: {Грешка}",
"verification_code": "Код за проверка: {код}"
} }
} }

View File

@ -862,5 +862,17 @@
"description": "Dieses Tool modifiziert die Datei workbench.desktop.main.js, um die Token -Grenze zu umgehen", "description": "Dieses Tool modifiziert die Datei workbench.desktop.main.js, um die Token -Grenze zu umgehen",
"press_enter": "Drücken Sie die Eingabetaste, um fortzufahren ...", "press_enter": "Drücken Sie die Eingabetaste, um fortzufahren ...",
"title": "Bypass Token Limit Tool" "title": "Bypass Token Limit Tool"
},
"tempmail": {
"no_email": "Keine Cursorüberprüfungs -E -Mail gefunden",
"general_error": "Es ist ein Fehler aufgetreten: {Fehler}",
"config_error": "Konfigurationsdateifehler: {Fehler}",
"checking_email": "Überprüfung nach Cursor -Überprüfungs -E -Mail ...",
"extract_code_failed": "Verifizierungscode extrahieren fehlgeschlagen: {Fehler}",
"configured_email": "Konfigurierte E -Mail: {E -Mail}",
"no_code": "Konnte keinen Bestätigungscode erhalten",
"check_email_failed": "Überprüfen Sie die E -Mail fehlgeschlagen: {Fehler}",
"email_found": "Gefundene Cursor -Überprüfungs -E -Mail gefunden",
"verification_code": "Überprüfungscode: {Code}"
} }
} }

View File

@ -191,6 +191,8 @@
"setting_password": "Setting Password", "setting_password": "Setting Password",
"manual_code_input": "Manual Code Input", "manual_code_input": "Manual Code Input",
"manual_email_input": "Manual Email Input", "manual_email_input": "Manual Email Input",
"suggest_email": "Suggested email: {suggested_email}",
"use_suggested_email_or_enter": "Type \"yes\" to use this email or enter your own email:",
"password": "Password", "password": "Password",
"first_name": "First Name", "first_name": "First Name",
"last_name": "Last Name", "last_name": "Last Name",
@ -850,5 +852,17 @@
"auth_updated_successfully": "Authentication information updated successfully!", "auth_updated_successfully": "Authentication information updated successfully!",
"auth_update_failed": "Failed to update authentication information", "auth_update_failed": "Failed to update authentication information",
"error": "Error: {error}" "error": "Error: {error}"
},
"tempmail": {
"check_email_failed": "Check email failed: {error}",
"extract_code_failed": "Extract verification code failed: {error}",
"configured_email": "Configured email: {email}",
"checking_email": "Checking for Cursor verification email...",
"email_found": "Found Cursor verification email",
"verification_code": "Verification code: {code}",
"no_code": "Could not get verification code",
"no_email": "No Cursor verification email found",
"config_error": "Config file error: {error}",
"general_error": "An error occurred: {error}"
} }
} }

View File

@ -862,5 +862,17 @@
"description": "Esta herramienta modifica el archivo workbench.desktop.main.js para evitar el límite del token", "description": "Esta herramienta modifica el archivo workbench.desktop.main.js para evitar el límite del token",
"press_enter": "Presione Entrar para continuar ...", "press_enter": "Presione Entrar para continuar ...",
"title": "Herramienta de límite de token de derivación" "title": "Herramienta de límite de token de derivación"
},
"tempmail": {
"general_error": "Se produjo un error: {error}",
"config_error": "Error de archivo de configuración: {error}",
"no_email": "No se encuentra el correo electrónico de verificación del cursor",
"checking_email": "Comprobación del correo electrónico de verificación del cursor ...",
"configured_email": "Correo electrónico configurado: {correo electrónico}",
"extract_code_failed": "Extraer el código de verificación fallido: {error}",
"no_code": "No pudo obtener el código de verificación",
"check_email_failed": "Verifique el correo electrónico fallido: {error}",
"email_found": "Correo electrónico de verificación del cursor encontrado",
"verification_code": "Código de verificación: {código}"
} }
} }

View File

@ -862,5 +862,17 @@
"description": "Cet outil modifie le fichier workbench.desktop.main.js pour contourner la limite de jeton", "description": "Cet outil modifie le fichier workbench.desktop.main.js pour contourner la limite de jeton",
"press_enter": "Appuyez sur Entrée pour continuer ...", "press_enter": "Appuyez sur Entrée pour continuer ...",
"title": "Outil de limite de jeton de contournement" "title": "Outil de limite de jeton de contournement"
},
"tempmail": {
"no_email": "Aucun e-mail de vérification du curseur trouvé",
"general_error": "Une erreur s'est produite: {erreur}",
"config_error": "Erreur de fichier de configuration: {erreur}",
"configured_email": "Email configuré: {e-mail}",
"extract_code_failed": "Extraire le code de vérification a échoué: {error}",
"checking_email": "Vérification du courrier électronique de vérification du curseur ...",
"email_found": "Email de vérification du curseur trouvé",
"no_code": "Impossible d'obtenir le code de vérification",
"check_email_failed": "Vérifier l'échec de l'e-mail: {Erreur}",
"verification_code": "Code de vérification: {code}"
} }
} }

View File

@ -850,5 +850,17 @@
"description": "Questo strumento modifica il file workbench.desktop.main.js per bypassare il limite token", "description": "Questo strumento modifica il file workbench.desktop.main.js per bypassare il limite token",
"press_enter": "Premere Invio per continuare ...", "press_enter": "Premere Invio per continuare ...",
"title": "Strumento di limite di bypass token" "title": "Strumento di limite di bypass token"
},
"tempmail": {
"config_error": "Errore del file di configurazione: {errore}",
"no_email": "Nessuna e -mail di verifica del cursore trovato",
"general_error": "Si è verificato un errore: {errore}",
"extract_code_failed": "Extract Verifica Codice non riuscito: {errore}",
"configured_email": "Email configurata: {email}",
"no_code": "Impossibile ottenere il codice di verifica",
"checking_email": "Verificare la verifica della verifica del cursore ...",
"check_email_failed": "Controlla l'e -mail non riuscita: {errore}",
"email_found": "Email di verifica del cursore trovato",
"verification_code": "Codice di verifica: {codice}"
} }
} }

View File

@ -850,5 +850,17 @@
"title": "手動カーソル認証", "title": "手動カーソル認証",
"updating_database": "カーソル認証データベースの更新...", "updating_database": "カーソル認証データベースの更新...",
"auth_update_failed": "認証情報の更新に失敗しました" "auth_update_failed": "認証情報の更新に失敗しました"
},
"tempmail": {
"general_error": "エラーが発生しました:{エラー}",
"no_email": "カーソル検証メールは見つかりません",
"config_error": "構成ファイルエラー:{エラー}",
"checking_email": "カーソル検証メールの確認...",
"extract_code_failed": "検証コードが失敗した抽出:{エラー}",
"configured_email": "構成された電子メール:{電子メール}",
"email_found": "カーソル検証メールが見つかりました",
"no_code": "確認コードを取得できませんでした",
"check_email_failed": "電子メールの失敗を確認する:{エラー}",
"verification_code": "検証コード:{code}"
} }
} }

View File

@ -862,5 +862,17 @@
"description": "Deze tool wijzigt het bestand Workbench.desktop.main.js om de tokenlimiet te omzeilen", "description": "Deze tool wijzigt het bestand Workbench.desktop.main.js om de tokenlimiet te omzeilen",
"press_enter": "Druk op Enter om door te gaan ...", "press_enter": "Druk op Enter om door te gaan ...",
"title": "Omzeilen token limiet tool" "title": "Omzeilen token limiet tool"
},
"tempmail": {
"no_email": "Geen cursorverificatie -e -mail gevonden",
"general_error": "Er is een fout opgetreden: {error}",
"config_error": "Config -bestandsfout: {error}",
"checking_email": "Controleren op cursorverificatie -e -mail ...",
"extract_code_failed": "Extract Verificatiecode mislukt: {error}",
"configured_email": "Geconfigureerd e -mail: {e -mail}",
"no_code": "Kon geen verificatiecode krijgen",
"email_found": "Cursor Verificatie -e -mail gevonden",
"check_email_failed": "Controleer e -mail mislukt: {error}",
"verification_code": "Verificatiecode: {code}"
} }
} }

View File

@ -862,5 +862,17 @@
"description": "Esta ferramenta modifica o arquivo workbench.desktop.main.js para ignorar o limite do token", "description": "Esta ferramenta modifica o arquivo workbench.desktop.main.js para ignorar o limite do token",
"press_enter": "Pressione Enter para continuar ...", "press_enter": "Pressione Enter para continuar ...",
"title": "Ipassue Token Limit Tool" "title": "Ipassue Token Limit Tool"
},
"tempmail": {
"config_error": "Erro de arquivo de configuração: {erro}",
"general_error": "Ocorreu um erro: {erro}",
"no_email": "Nenhum e -mail de verificação do cursor encontrado",
"extract_code_failed": "Código de verificação de extração falhou: {erro}",
"checking_email": "Verificando o e -mail de verificação do cursor ...",
"configured_email": "Email configurado: {email}",
"no_code": "Não foi possível obter o código de verificação",
"check_email_failed": "Verifique o e -mail falhado: {erro}",
"verification_code": "Código de verificação: {code}",
"email_found": "E -mail de verificação do cursor encontrado"
} }
} }

View File

@ -862,5 +862,17 @@
"description": "Этот инструмент изменяет файл workbench.desktop.main.js, чтобы обойти предел токена", "description": "Этот инструмент изменяет файл workbench.desktop.main.js, чтобы обойти предел токена",
"press_enter": "Нажмите Enter, чтобы продолжить ...", "press_enter": "Нажмите Enter, чтобы продолжить ...",
"title": "Инструмент ограничения обхода токена" "title": "Инструмент ограничения обхода токена"
},
"tempmail": {
"no_email": "Электронное письмо с проверкой курсора не найдено",
"config_error": "Ошибка файла конфигурации: {ошибка}",
"extract_code_failed": "Установка кода извлечения проверки: {ошибка}",
"general_error": "Произошла ошибка: {ошибка}",
"no_code": "Не удалось получить код проверки",
"checking_email": "Проверка на проверку курсора по электронной почте ...",
"configured_email": "Настройка электронной почты: {электронная почта}",
"check_email_failed": "Проверка по электронной почте не удастся: {ошибка}",
"verification_code": "Код проверки: {код}",
"email_found": "Найдено электронное письмо с проверкой курсора"
} }
} }

View File

@ -862,5 +862,17 @@
"description": "Bu araç, jeton sınırını atlamak için workbench.desktop.main.js dosyasını değiştirir", "description": "Bu araç, jeton sınırını atlamak için workbench.desktop.main.js dosyasını değiştirir",
"press_enter": "Devam etmek için Enter tuşuna basın ...", "press_enter": "Devam etmek için Enter tuşuna basın ...",
"title": "Baypas Token Limit Aracı" "title": "Baypas Token Limit Aracı"
},
"tempmail": {
"general_error": "Bir hata oluştu: {hata}",
"no_email": "İmleç doğrulama e -postası bulunamadı",
"config_error": "Yapılandırma dosya hatası: {error}",
"extract_code_failed": ıkarma Doğrulama Kodu Başarısız: {Hata}",
"configured_email": "Yapılandırılmış e -posta: {e -posta}",
"checking_email": "İmleç doğrulama e -postasını kontrol etmek ...",
"check_email_failed": "E -postanın başarısız olduğunu kontrol edin: {hata}",
"no_code": "Doğrulama kodu alamadı",
"email_found": "İmleç doğrulama e -postası bulundu",
"verification_code": "Doğrulama kodu: {kod}"
} }
} }

View File

@ -863,5 +863,17 @@
"profile": "Hồ sơ {Number}", "profile": "Hồ sơ {Number}",
"profile_list": "Có sẵn {trình duyệt} Hồ sơ:", "profile_list": "Có sẵn {trình duyệt} Hồ sơ:",
"invalid_selection": "Lựa chọn không hợp lệ. Hãy thử lại." "invalid_selection": "Lựa chọn không hợp lệ. Hãy thử lại."
},
"tempmail": {
"config_error": "Lỗi tệp cấu hình: {error}",
"general_error": "Đã xảy ra lỗi: {lỗi}",
"no_email": "Không tìm thấy email xác minh con trỏ",
"checking_email": "Kiểm tra email xác minh con trỏ ...",
"configured_email": "Email được định cấu hình: {email}",
"extract_code_failed": "Trích xuất mã xác minh không thành công: {error}",
"no_code": "Không thể nhận mã xác minh",
"check_email_failed": "Kiểm tra email không thành công: {lỗi}",
"email_found": "Tìm thấy email xác minh con trỏ",
"verification_code": "Mã xác minh: {code}"
} }
} }

View File

@ -191,6 +191,8 @@
"setting_password": "设置密码", "setting_password": "设置密码",
"manual_code_input": "手动输入验证码", "manual_code_input": "手动输入验证码",
"manual_email_input": "手动输入邮箱", "manual_email_input": "手动输入邮箱",
"suggest_email": "推荐邮箱地址: {suggested_email}",
"use_suggested_email_or_enter": "输入\"yes\"使用此邮箱或直接输入您想使用的邮箱地址:",
"password": "密码", "password": "密码",
"first_name": "名字", "first_name": "名字",
"last_name": "姓氏", "last_name": "姓氏",
@ -854,5 +856,17 @@
"title": "手动Cursor身份验证", "title": "手动Cursor身份验证",
"token_verified": "令牌成功验证了!", "token_verified": "令牌成功验证了!",
"updating_database": "更新Cursor身份验证数据库..." "updating_database": "更新Cursor身份验证数据库..."
},
"tempmail": {
"general_error": "发生错误:{error}",
"no_email": "找不到Cursor验证电子邮件",
"configured_email": "配置的电子邮件:{email}",
"config_error": "配置文件错误:{error}",
"extract_code_failed": "提取验证代码失败:{error}",
"no_code": "无法获得验证代码",
"check_email_failed": "检查电子邮件失败:{error}",
"checking_email": "检查Cursor验证电子邮件...",
"email_found": "找到Cursor验证电子邮件",
"verification_code": "验证代码:{code}"
} }
} }

View File

@ -188,6 +188,8 @@
"setting_password": "設置密碼", "setting_password": "設置密碼",
"manual_code_input": "手動輸入驗證碼", "manual_code_input": "手動輸入驗證碼",
"manual_email_input": "手動輸入郵箱地址", "manual_email_input": "手動輸入郵箱地址",
"suggest_email": "推薦郵箱地址: {suggested_email}",
"use_suggested_email_or_enter": "輸入\"yes\"使用此郵箱或直接輸入您想使用的郵箱地址:",
"password": "密碼", "password": "密碼",
"first_name": "名字", "first_name": "名字",
"last_name": "姓氏", "last_name": "姓氏",
@ -869,5 +871,17 @@
"title": "手動Cursor身份驗證", "title": "手動Cursor身份驗證",
"updating_database": "更新Cursor身份驗證數據庫...", "updating_database": "更新Cursor身份驗證數據庫...",
"auth_update_failed": "無法更新身份驗證信息" "auth_update_failed": "無法更新身份驗證信息"
},
"tempmail": {
"general_error": "發生錯誤:{error}",
"config_error": "配置文件錯誤:{error}",
"no_email": "找不到Cursor驗證電子郵件",
"checking_email": "檢查Cursor驗證電子郵件...",
"extract_code_failed": "提取驗證代碼失敗:{error}",
"configured_email": "配置的電子郵件:{email}",
"no_code": "無法獲得驗證代碼",
"check_email_failed": "檢查電子郵件失敗:{error}",
"email_found": "找到Cursor驗證電子郵件",
"verification_code": "驗證代碼:{code}"
} }
} }

View File

@ -116,7 +116,14 @@ def fill_signup_form(page, first_name, last_name, email, config, translator=None
def get_user_documents_path(): def get_user_documents_path():
"""Get user Documents folder path""" """Get user Documents folder path"""
if sys.platform == "win32": if sys.platform == "win32":
return os.path.join(os.path.expanduser("~"), "Documents") try:
import winreg
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") as key:
documents_path, _ = winreg.QueryValueEx(key, "Personal")
return documents_path
except Exception as e:
# fallback
return os.path.join(os.path.expanduser("~"), "Documents")
elif sys.platform == "darwin": elif sys.platform == "darwin":
return os.path.join(os.path.expanduser("~"), "Documents") return os.path.join(os.path.expanduser("~"), "Documents")
else: # Linux else: # Linux

View File

@ -33,7 +33,14 @@ EMOJI = {
def get_user_documents_path(): def get_user_documents_path():
"""Get user Documents folder path""" """Get user Documents folder path"""
if sys.platform == "win32": if sys.platform == "win32":
return os.path.join(os.path.expanduser("~"), "Documents") try:
import winreg
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") as key:
documents_path, _ = winreg.QueryValueEx(key, "Personal")
return documents_path
except Exception as e:
# fallback
return os.path.join(os.path.expanduser("~"), "Documents")
elif sys.platform == "darwin": elif sys.platform == "darwin":
return os.path.join(os.path.expanduser("~"), "Documents") return os.path.join(os.path.expanduser("~"), "Documents")
else: # Linux else: # Linux

View File

@ -124,76 +124,62 @@ function Install-CursorFreeVIP {
} }
Write-Styled "No existing installation file found, starting download..." -Color $Theme.Primary -Prefix "Download" 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")
# Define progress variables # Use HttpWebRequest for chunked download with real-time progress bar
$Global:downloadedBytes = 0 $url = $asset.browser_download_url
$Global:totalBytes = 0 $outputFile = $downloadPath
$Global:lastProgress = 0 Write-Styled "Downloading from: $url" -Color $Theme.Info -Prefix "URL"
$Global:lastBytes = 0 Write-Styled "Saving to: $outputFile" -Color $Theme.Info -Prefix "Path"
$Global:lastTime = Get-Date
# Download progress event $request = [System.Net.HttpWebRequest]::Create($url)
$eventId = [guid]::NewGuid() $request.UserAgent = "PowerShell Script"
Register-ObjectEvent -InputObject $webClient -EventName DownloadProgressChanged -Action { $response = $request.GetResponse()
$Global:downloadedBytes = $EventArgs.BytesReceived $totalLength = $response.ContentLength
$Global:totalBytes = $EventArgs.TotalBytesToReceive $responseStream = $response.GetResponseStream()
$progress = [math]::Round(($Global:downloadedBytes / $Global:totalBytes) * 100, 1) $fileStream = [System.IO.File]::OpenWrite($outputFile)
$buffer = New-Object byte[] 8192
# Only update display when progress changes by more than 1% $bytesRead = 0
if ($progress -gt $Global:lastProgress + 1) { $totalRead = 0
$Global:lastProgress = $progress $lastProgress = -1
$downloadedMB = [math]::Round($Global:downloadedBytes / 1MB, 2) $startTime = Get-Date
$totalMB = [math]::Round($Global:totalBytes / 1MB, 2) try {
do {
# Calculate download speed $bytesRead = $responseStream.Read($buffer, 0, $buffer.Length)
$currentTime = Get-Date if ($bytesRead -gt 0) {
$timeSpan = ($currentTime - $Global:lastTime).TotalSeconds $fileStream.Write($buffer, 0, $bytesRead)
if ($timeSpan -gt 0) { $totalRead += $bytesRead
$bytesChange = $Global:downloadedBytes - $Global:lastBytes $progress = [math]::Round(($totalRead / $totalLength) * 100, 1)
$speed = $bytesChange / $timeSpan if ($progress -ne $lastProgress) {
$elapsed = (Get-Date) - $startTime
# Choose appropriate unit based on speed $speed = if ($elapsed.TotalSeconds -gt 0) { $totalRead / $elapsed.TotalSeconds } else { 0 }
$speedDisplay = if ($speed -gt 1MB) { $speedDisplay = if ($speed -gt 1MB) {
"$([math]::Round($speed / 1MB, 2)) MB/s" "{0:N2} MB/s" -f ($speed / 1MB)
} elseif ($speed -gt 1KB) { } elseif ($speed -gt 1KB) {
"$([math]::Round($speed / 1KB, 2)) KB/s" "{0:N2} KB/s" -f ($speed / 1KB)
} else { } else {
"$([math]::Round($speed, 2)) B/s" "{0:N2} B/s" -f $speed
}
$downloadedMB = [math]::Round($totalRead / 1MB, 2)
$totalMB = [math]::Round($totalLength / 1MB, 2)
Write-Progress -Activity "Downloading CursorFreeVIP" -Status "$downloadedMB MB / $totalMB MB ($progress%) - $speedDisplay" -PercentComplete $progress
$lastProgress = $progress
} }
Write-Host "`rDownloading: $downloadedMB MB / $totalMB MB ($progress%) - $speedDisplay" -NoNewline -ForegroundColor Cyan
# Update last data
$Global:lastBytes = $Global:downloadedBytes
$Global:lastTime = $currentTime
} }
} } while ($bytesRead -gt 0)
} | Out-Null } finally {
$fileStream.Close()
# Download completed event $responseStream.Close()
Register-ObjectEvent -InputObject $webClient -EventName DownloadFileCompleted -Action { $response.Close()
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-Progress -Activity "Downloading CursorFreeVIP" -Completed
Write-Styled "File location: $downloadPath" -Color $Theme.Info -Prefix "Location" # Check file exists and is not zero size
if (!(Test-Path $outputFile) -or ((Get-Item $outputFile).Length -eq 0)) {
throw "Download failed or file is empty."
}
Write-Styled "Download completed!" -Color $Theme.Success -Prefix "Complete"
Write-Styled "File location: $outputFile" -Color $Theme.Info -Prefix "Location"
Write-Styled "Starting program..." -Color $Theme.Primary -Prefix "Launch" Write-Styled "Starting program..." -Color $Theme.Primary -Prefix "Launch"
Start-Process $outputFile
# Run program
Start-Process $downloadPath
} }
catch { catch {
Write-Styled $_.Exception.Message -Color $Theme.Error -Prefix "Error" Write-Styled $_.Exception.Message -Color $Theme.Error -Prefix "Error"

View File

@ -32,7 +32,13 @@ EMOJI = {
def get_user_documents_path(): def get_user_documents_path():
"""Get user Documents folder path""" """Get user Documents folder path"""
if sys.platform == "win32": if sys.platform == "win32":
return os.path.join(os.path.expanduser("~"), "Documents") try:
import winreg
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") as key:
documents_path, _ = winreg.QueryValueEx(key, "Personal")
return documents_path
except Exception as e:
return os.path.join(os.path.expanduser("~"), "Documents")
elif sys.platform == "darwin": elif sys.platform == "darwin":
return os.path.join(os.path.expanduser("~"), "Documents") return os.path.join(os.path.expanduser("~"), "Documents")
else: # Linux else: # Linux

View File

@ -6,7 +6,16 @@ import random
def get_user_documents_path(): def get_user_documents_path():
"""Get user documents path""" """Get user documents path"""
if platform.system() == "Windows": if platform.system() == "Windows":
return os.path.expanduser("~\\Documents") try:
import winreg
# 打开注册表
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") as key:
# 获取 "Personal" 键的值,这指向用户的文档目录
documents_path, _ = winreg.QueryValueEx(key, "Personal")
return documents_path
except Exception as e:
# fallback
return os.path.expanduser("~\\Documents")
else: else:
return os.path.expanduser("~/Documents") return os.path.expanduser("~/Documents")