Files
auto_cursor_online/menu.py
2025-03-31 09:55:54 +08:00

561 lines
19 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import asyncio
import sys
import os
from datetime import datetime
from typing import Dict, Any, List, Callable, Awaitable
from loguru import logger
# 导入功能模块
import upload_accounts
import reset_extracted
import reupload_all
try:
import retry_failed
has_retry_failed = True
except ImportError:
has_retry_failed = False
try:
import reset_retrying
has_reset_retrying = True
except ImportError:
has_reset_retrying = False
try:
import delete_db
has_delete_db = True
except ImportError:
has_delete_db = False
from core.config import Config
from core.logger import setup_logger
from core.database import DatabaseManager
class MenuSystem:
def __init__(self):
self.config = Config.from_yaml()
self.logger = setup_logger(self.config)
self.db_manager = DatabaseManager(self.config)
# 定义菜单项
self.menu_items = [
{
"key": "1",
"title": "重新上传所有账号",
"description": "重置所有账号的提取状态并重新上传到API服务器推荐",
"handler": self.reupload_all_menu
},
{
"key": "2",
"title": "上传账号到API",
"description": "将注册成功的账号上传到API服务器",
"handler": self.upload_accounts_menu
},
{
"key": "3",
"title": "重置账号提取状态",
"description": "将账号的extracted字段重置为0允许重新上传",
"handler": self.reset_extracted_menu
}
]
# 添加可选功能
if has_retry_failed:
self.menu_items.append({
"key": "4",
"title": "重试失败账号",
"description": "重新尝试注册失败的账号",
"handler": self.retry_failed_menu
})
if has_reset_retrying:
self.menu_items.append({
"key": "5",
"title": "重置正在重试的账号",
"description": "将状态为retrying的账号重置为failed",
"handler": self.reset_retrying_menu
})
if has_delete_db:
self.menu_items.append({
"key": "6",
"title": "删除数据库记录",
"description": "根据条件删除数据库中的记录",
"handler": self.delete_db_menu
})
# 添加退出选项
self.menu_items.append({
"key": "q",
"title": "退出程序",
"description": "退出菜单系统",
"handler": self.exit_menu
})
async def initialize(self):
"""初始化数据库连接"""
await self.db_manager.initialize()
async def cleanup(self):
"""清理资源"""
await self.db_manager.cleanup()
async def show_menu(self):
"""显示主菜单"""
os.system('cls' if os.name == 'nt' else 'clear')
print("\n===== Cursor 账号管理系统 =====\n")
# 显示菜单项
for item in self.menu_items:
print(f"{item['key']}. {item['title']} - {item['description']}")
print("\n请选择功能 (输入对应数字或q退出):", end=" ")
choice = input().strip().lower()
# 查找选择的菜单项
selected_item = next((item for item in self.menu_items if item["key"] == choice), None)
if selected_item:
await selected_item["handler"]()
else:
print("\n无效的选择,请重试!")
input("按Enter键继续...")
await self.show_menu()
async def upload_accounts_menu(self):
"""上传账号菜单"""
os.system('cls' if os.name == 'nt' else 'clear')
print("\n===== 上传账号到API =====\n")
# 统计账号状态
resetter = reset_extracted.ExtractedResetter()
await resetter.initialize()
stats = await resetter.count_success_accounts()
await resetter.cleanup()
print(f"当前状态: 总成功账号: {stats['total']}, 已提取: {stats['extracted']}, 未提取: {stats['not_extracted']}")
if stats['not_extracted'] == 0:
print("\n没有待上传的账号。是否要重置所有账号的提取状态?(y/n)", end=" ")
reset_choice = input().strip().lower()
if reset_choice == 'y':
await self.reset_all_extracted()
print("\n已重置所有账号的提取状态,现在可以上传。")
else:
print("\n未重置状态,无法上传账号。")
input("\n按Enter键返回主菜单...")
return
print("\n选项:")
print("1. 预览待上传账号 (dry-run)")
print("2. 上传所有账号")
print("3. 上传指定批次数量")
print("4. 修改批次大小 (默认: 100)")
print("5. 禁用代理")
print("b. 返回主菜单")
choice = input("\n请选择操作: ").strip().lower()
args = []
use_proxy = True
batch_size = 100
max_batches = 0
if choice == "1":
args = ["--dry-run"]
elif choice == "2":
args = [] # 使用默认设置上传所有
elif choice == "3":
try:
batches = int(input("请输入要处理的批次数量: ").strip())
if batches > 0:
args = [f"--batches", f"{batches}"]
max_batches = batches
else:
print("批次数量必须大于0")
input("按Enter键继续...")
await self.upload_accounts_menu()
return
except ValueError:
print("无效的输入,必须是整数")
input("按Enter键继续...")
await self.upload_accounts_menu()
return
elif choice == "4":
try:
size = int(input("请输入批次大小: ").strip())
if size > 0:
batch_size = size
args = [f"--batch-size", f"{size}"]
else:
print("批次大小必须大于0")
input("按Enter键继续...")
await self.upload_accounts_menu()
return
except ValueError:
print("无效的输入,必须是整数")
input("按Enter键继续...")
await self.upload_accounts_menu()
return
elif choice == "5":
use_proxy = False
args = ["--no-proxy"]
elif choice == "b":
await self.show_menu()
return
else:
print("无效的选择,请重试!")
input("按Enter键继续...")
await self.upload_accounts_menu()
return
# 处理输入的批次大小和批次数量组合
if choice == "3" and choice == "4":
args = [f"--batches", f"{max_batches}", f"--batch-size", f"{batch_size}"]
# 添加代理设置
if not use_proxy and "--no-proxy" not in args:
args.append("--no-proxy")
print(f"\n准备执行命令: python upload_accounts.py {' '.join(args)}")
print("按Enter键开始执行或按Ctrl+C取消...")
input()
# 存储原始sys.argv并替换
original_argv = sys.argv.copy()
sys.argv = [sys.argv[0]] + args
try:
# 执行上传账号功能
await upload_accounts.main()
except Exception as e:
self.logger.error(f"执行上传账号出错: {e}")
finally:
# 恢复sys.argv
sys.argv = original_argv
input("\n操作完成按Enter键返回主菜单...")
await self.show_menu()
async def reset_extracted_menu(self):
"""重置提取状态菜单"""
os.system('cls' if os.name == 'nt' else 'clear')
print("\n===== 重置账号提取状态 =====\n")
# 统计账号状态
resetter = reset_extracted.ExtractedResetter()
await resetter.initialize()
stats = await resetter.count_success_accounts()
print(f"当前状态: 总成功账号: {stats['total']}, 已提取: {stats['extracted']}, 未提取: {stats['not_extracted']}")
print("\n选项:")
print("1. 预览账号状态 (dry-run)")
print("2. 重置所有账号的提取状态")
print("3. 重置指定模式的账号提取状态")
print("b. 返回主菜单")
choice = input("\n请选择操作: ").strip().lower()
args = []
if choice == "1":
args = ["--dry-run"]
elif choice == "2":
print("\n确定要重置所有账号的提取状态吗?这将允许已提取的账号再次上传。(y/n)", end=" ")
confirm = input().strip().lower()
if confirm != 'y':
print("操作已取消")
input("按Enter键继续...")
await self.reset_extracted_menu()
return
elif choice == "3":
pattern = input("请输入邮箱匹配模式 (例如: outlook.com): ").strip()
if pattern:
args = ["--pattern", pattern]
else:
print("模式不能为空")
input("按Enter键继续...")
await self.reset_extracted_menu()
return
elif choice == "b":
await self.show_menu()
return
else:
print("无效的选择,请重试!")
input("按Enter键继续...")
await self.reset_extracted_menu()
return
# 执行重置
print(f"\n准备执行命令: python reset_extracted.py {' '.join(args)}")
print("按Enter键开始执行或按Ctrl+C取消...")
input()
# 存储原始sys.argv并替换
original_argv = sys.argv.copy()
sys.argv = [sys.argv[0]] + args
try:
# 执行重置操作
await reset_extracted.main()
except Exception as e:
self.logger.error(f"执行重置提取状态出错: {e}")
finally:
# 恢复sys.argv
sys.argv = original_argv
await resetter.cleanup()
input("\n操作完成按Enter键返回主菜单...")
await self.show_menu()
async def reupload_all_menu(self):
"""重新上传所有账号菜单"""
os.system('cls' if os.name == 'nt' else 'clear')
print("\n===== 重新上传所有账号 =====\n")
print("此操作将:")
print("1. 重置所有成功账号的提取状态")
print("2. 重新上传所有账号到API服务器")
print("\n警告: 此操作可能需要较长时间,请确保网络连接稳定。")
print("是否继续? (y/n)", end=" ")
choice = input().strip().lower()
if choice != 'y':
print("\n操作已取消")
input("\n按Enter键返回主菜单...")
await self.show_menu()
return
try:
# 执行重新上传
await reupload_all.main()
except Exception as e:
self.logger.error(f"重新上传过程中出错: {e}")
finally:
input("\n操作完成按Enter键返回主菜单...")
await self.show_menu()
async def retry_failed_menu(self):
"""重试失败账号菜单"""
if not has_retry_failed:
print("\n功能不可用: retry_failed.py 未找到")
input("按Enter键返回主菜单...")
await self.show_menu()
return
os.system('cls' if os.name == 'nt' else 'clear')
print("\n===== 重试失败账号 =====\n")
print("此功能将重新尝试注册失败的账号。")
# 这里可以添加更多的统计信息显示
print("\n选项:")
print("1. 执行账号重试")
print("b. 返回主菜单")
choice = input("\n请选择操作: ").strip().lower()
if choice == "1":
# 执行重试失败账号功能
print("\n准备重试失败账号...")
print("按Enter键开始执行或按Ctrl+C取消...")
input()
# 存储原始sys.argv
original_argv = sys.argv.copy()
sys.argv = [sys.argv[0]]
try:
# 执行重试功能
await retry_failed.main()
except Exception as e:
self.logger.error(f"执行重试失败账号出错: {e}")
finally:
# 恢复sys.argv
sys.argv = original_argv
elif choice == "b":
await self.show_menu()
return
else:
print("无效的选择,请重试!")
input("按Enter键继续...")
await self.retry_failed_menu()
return
input("\n操作完成按Enter键返回主菜单...")
await self.show_menu()
async def reset_retrying_menu(self):
"""重置正在重试的账号菜单"""
if not has_reset_retrying:
print("\n功能不可用: reset_retrying.py 未找到")
input("按Enter键返回主菜单...")
await self.show_menu()
return
os.system('cls' if os.name == 'nt' else 'clear')
print("\n===== 重置正在重试的账号 =====\n")
print("此功能将状态为retrying的账号重置为failed。")
# 这里可以添加更多的统计信息显示
print("\n选项:")
print("1. 执行重置retrying状态")
print("b. 返回主菜单")
choice = input("\n请选择操作: ").strip().lower()
if choice == "1":
# 执行重置retrying状态功能
print("\n准备重置正在重试的账号...")
print("按Enter键开始执行或按Ctrl+C取消...")
input()
# 存储原始sys.argv
original_argv = sys.argv.copy()
sys.argv = [sys.argv[0]]
try:
# 执行重置功能
await reset_retrying.main()
except Exception as e:
self.logger.error(f"执行重置retrying状态出错: {e}")
finally:
# 恢复sys.argv
sys.argv = original_argv
elif choice == "b":
await self.show_menu()
return
else:
print("无效的选择,请重试!")
input("按Enter键继续...")
await self.reset_retrying_menu()
return
input("\n操作完成按Enter键返回主菜单...")
await self.show_menu()
async def delete_db_menu(self):
"""删除数据库记录菜单"""
if not has_delete_db:
print("\n功能不可用: delete_db.py 未找到")
input("按Enter键返回主菜单...")
await self.show_menu()
return
os.system('cls' if os.name == 'nt' else 'clear')
print("\n===== 删除数据库记录 =====\n")
print("此功能将根据条件删除数据库中的记录。")
print("警告: 删除操作不可恢复,请谨慎操作!")
print("\n选项:")
print("1. 交互式删除(按状态)")
print("2. 删除所有记录")
print("b. 返回主菜单")
choice = input("\n请选择操作: ").strip().lower()
if choice == "b":
await self.show_menu()
return
elif choice == "2":
print("\n警告: 此操作将删除数据库中的所有记录!")
print("确定要继续吗?(y/n)", end=" ")
confirm = input().strip().lower()
if confirm != 'y':
print("操作已取消")
input("按Enter键继续...")
await self.delete_db_menu()
return
# 执行全部删除
args = ["--all", "--confirm"]
print(f"\n准备执行命令: python delete_db.py {' '.join(args)}")
print("按Enter键开始执行或按Ctrl+C取消...")
input()
# 存储原始sys.argv
original_argv = sys.argv.copy()
sys.argv = [sys.argv[0]] + args
try:
# 执行删除功能
await delete_db.main()
except Exception as e:
self.logger.error(f"执行删除数据库记录出错: {e}")
finally:
# 恢复sys.argv
sys.argv = original_argv
input("\n操作完成按Enter键返回主菜单...")
await self.show_menu()
return
elif choice == "1":
# 执行交互式删除
args = ["--interactive"]
print(f"\n准备执行命令: python delete_db.py {' '.join(args)}")
print("按Enter键开始执行或按Ctrl+C取消...")
input()
# 存储原始sys.argv
original_argv = sys.argv.copy()
sys.argv = [sys.argv[0]] + args
try:
# 执行删除功能
await delete_db.main()
except Exception as e:
self.logger.error(f"执行删除数据库记录出错: {e}")
finally:
# 恢复sys.argv
sys.argv = original_argv
input("\n操作完成按Enter键返回主菜单...")
await self.show_menu()
return
else:
print("无效的选择,请重试!")
input("按Enter键继续...")
await self.delete_db_menu()
return
async def reset_all_extracted(self):
"""重置所有账号的提取状态"""
resetter = reset_extracted.ExtractedResetter()
await resetter.initialize()
try:
await resetter.reset_extracted()
finally:
await resetter.cleanup()
async def exit_menu(self):
"""退出菜单"""
print("\n感谢使用,再见!")
sys.exit(0)
async def main():
menu = MenuSystem()
try:
await menu.initialize()
await menu.show_menu()
except KeyboardInterrupt:
print("\n程序被用户中断")
except Exception as e:
logger.error(f"程序执行出错: {e}")
finally:
await menu.cleanup()
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\n程序被用户中断")
except Exception as e:
print(f"程序崩溃: {e}")