first commit

This commit is contained in:
jianxin committed 2025-04-02 21:01:25 +08:00
commit 4890793ce5
1029 files changed
+5992

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
"""配置管理模块."""
# 使 config 目录成为 Python 包
+127
View File
@@ -0,0 +1,127 @@
"""
环境配置模块,用于控制应用在不同环境(开发/生产)中的行为
"""
import os
import logging
import json
from pathlib import Path
from typing import Dict, Any
# 默认配置
DEFAULT_CONFIG = {
"environment": "development", # 可选:development, production
"log_level": {"development": "DEBUG", "production": "WARNING"},
"production_headless": True, # 生产环境是否使用无头浏览器
"data_dir": "data", # 数据存储目录
"config_dir": "config", # 配置文件目录
"log_dir": "logs", # 日志文件目录
}
class EnvironmentManager:
"""环境配置管理类"""
def __init__(self, config_file: str = None):
# 默认配置文件路径
self.app_dir = Path(__file__).parent.parent.parent
self.config_file = config_file or self.app_dir / "config" / "environment.json"
self.config = DEFAULT_CONFIG.copy()
# 尝试加载配置文件
self._load_config()
# 初始化日志配置
self._setup_logging()
def _load_config(self) -> Dict[str, Any]:
"""加载配置文件"""
try:
if os.path.exists(self.config_file):
with open(self.config_file, "r", encoding="utf-8") as f:
file_config = json.load(f)
self.config.update(file_config)
return self.config
except Exception as e:
print(f"加载配置文件失败: {str(e)},使用默认配置")
return self.config
def _setup_logging(self):
"""设置日志级别"""
env = self.config.get("environment", "development")
log_level_name = self.config.get("log_level", {}).get(env, "INFO")
# 将字符串转换为日志级别
log_level = getattr(logging, log_level_name, logging.INFO)
# 设置根日志记录器的级别
root_logger = logging.getLogger("douyin_imbot")
root_logger.setLevel(log_level)
# 如果没有处理器,添加一个控制台处理器
if not root_logger.handlers:
handler = logging.StreamHandler()
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
handler.setFormatter(formatter)
root_logger.addHandler(handler)
# 如果是生产环境,还添加一个文件处理器
if env == "production":
log_dir = self.app_dir / self.config.get("log_dir", "logs")
os.makedirs(log_dir, exist_ok=True)
log_file = log_dir / f"douyin_imbot.log"
file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(formatter)
root_logger.addHandler(file_handler)
def get_setting(self, key: str, default=None) -> Any:
"""获取特定配置项的值"""
return self.config.get(key, default)
def get_all_settings(self) -> Dict[str, Any]:
"""获取所有配置"""
return self.config.copy()
def update_setting(self, key: str, value: Any) -> bool:
"""更新配置项"""
try:
self.config[key] = value
return self._save_config()
except Exception as e:
print(f"更新配置失败: {str(e)}")
return False
def _save_config(self) -> bool:
"""保存配置到文件"""
try:
# 确保目录存在
os.makedirs(os.path.dirname(self.config_file), exist_ok=True)
with open(self.config_file, "w", encoding="utf-8") as f:
json.dump(self.config, f, indent=2, ensure_ascii=False)
return True
except Exception as e:
print(f"保存配置文件失败: {str(e)}")
return False
@property
def is_production(self) -> bool:
"""是否为生产环境"""
return self.config.get("environment", "").lower() == "production"
@property
def is_development(self) -> bool:
"""是否为开发环境"""
return not self.is_production
# 创建一个单例实例
env_manager = EnvironmentManager()
def get_environment_settings():
"""获取环境设置的辅助函数"""
return env_manager.get_all_settings()
+245
View File
@@ -0,0 +1,245 @@
import os
import json
import logging
import sys
from pathlib import Path
from typing import Dict, List, Optional, Any, Union
import uuid
from datetime import datetime
from pydantic import BaseModel, Field
logger = logging.getLogger(__name__)
# 更新默认设置以包含浏览器配置文件
DEFAULT_SETTINGS = {
"api_key": "",
"message_interval": 5,
"auto_start": False,
"theme": "system",
"color_theme": "blue",
"profiles_dir": os.path.join(os.path.expanduser("~"), "DouYinBot_Browser_Cache"),
"browser_profiles": [],
}
class UserProfile(BaseModel):
"""Chrome用户配置文件模型."""
profile_id: str
profile_name: str
douyin_account: Optional[str] = None
profile_path: Optional[str] = None
enabled: bool = True
auto_reply_enabled: bool = True
class ReplyTemplate(BaseModel):
"""回复模板模型."""
template_id: str
name: str
content: str
keywords: List[str] = Field(default_factory=list)
is_default: bool = False
class Settings(BaseModel):
"""应用程序设置模型."""
chrome_executable_path: Optional[str] = None
profiles: List[UserProfile] = Field(default_factory=list)
reply_templates: List[ReplyTemplate] = Field(default_factory=list)
check_interval_seconds: int = 60
headless: bool = False
auto_start_on_launch: bool = False
class BrowserProfile(BaseModel):
"""浏览器用户配置文件模型."""
profile_id: str = Field(default_factory=lambda: str(uuid.uuid4()))
profile_name: str
profile_dir: str
enabled: bool = True
douyin_account: Optional[str] = None
auto_reply_enabled: bool = True
creation_time: str = Field(default_factory=lambda: datetime.now().isoformat())
last_used_time: Optional[str] = None
def get_config_dir() -> Path:
"""获取配置目录."""
config_dir = Path.home() / ".douyin-imbot"
config_dir.mkdir(exist_ok=True)
return config_dir
def get_config_path() -> Path:
"""获取配置文件路径."""
return get_config_dir() / "settings.json"
def load_settings() -> Settings:
"""加载应用程序设置."""
config_path = get_config_path()
if not config_path.exists():
# 创建默认设置
settings = Settings()
save_settings(settings)
return settings
try:
with open(config_path, "r", encoding="utf-8") as f:
data = json.load(f)
return Settings.model_validate(data)
except Exception as e:
print(f"加载设置时出错: {e}")
# 返回默认设置
return Settings()
def save_settings(settings: Settings) -> None:
"""保存应用程序设置."""
config_path = get_config_path()
try:
with open(config_path, "w", encoding="utf-8") as f:
json.dump(settings.model_dump(), f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"保存设置时出错: {e}")
def find_chrome_installations() -> List[str]:
"""查找系统中的Chrome安装."""
possible_paths = []
# Windows上的常见Chrome安装路径
if os.name == "nt":
program_files = os.environ.get("PROGRAMFILES", "C:\\Program Files")
program_files_x86 = os.environ.get(
"PROGRAMFILES(X86)", "C:\\Program Files (x86)"
)
paths = [
Path(program_files) / "Google" / "Chrome" / "Application" / "chrome.exe",
Path(program_files_x86)
/ "Google"
/ "Chrome"
/ "Application"
/ "chrome.exe",
Path(os.environ.get("LOCALAPPDATA", ""))
/ "Google"
/ "Chrome"
/ "Application"
/ "chrome.exe",
]
for path in paths:
if path.exists():
possible_paths.append(str(path))
# macOS上的Chrome路径
elif sys.platform == "darwin":
paths = [
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
f"/Users/{os.getlogin()}/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
]
for path in paths:
if os.path.exists(path):
possible_paths.append(path)
# Linux上的Chrome路径
elif sys.platform.startswith("linux"):
paths = ["/usr/bin/google-chrome", "/usr/bin/google-chrome-stable"]
for path in paths:
if os.path.exists(path):
possible_paths.append(path)
return possible_paths
def find_chrome_user_data_dir() -> Optional[str]:
"""尝试找到Chrome用户数据目录."""
if os.name == "nt": # Windows
return os.path.join(
os.environ.get("LOCALAPPDATA", ""), "Google", "Chrome", "User Data"
)
elif sys.platform == "darwin": # macOS
return os.path.expanduser("~/Library/Application Support/Google/Chrome")
elif sys.platform.startswith("linux"): # Linux
return os.path.expanduser("~/.config/google-chrome")
return None
def load_settings():
"""
从配置文件加载设置,如果文件不存在则使用默认设置
Returns:
dict: 设置字典
"""
settings_path = get_settings_path()
try:
if os.path.exists(settings_path):
with open(settings_path, "r", encoding="utf-8") as f:
settings = json.load(f)
logger.info("已从文件加载设置")
# 确保所有默认设置键都存在
for key, value in DEFAULT_SETTINGS.items():
if key not in settings:
settings[key] = value
# 确保浏览器配置文件列表存在
if "browser_profiles" not in settings:
settings["browser_profiles"] = []
return settings
except Exception as e:
logger.error(f"加载设置时出错: {str(e)}")
logger.info("使用默认设置")
return DEFAULT_SETTINGS.copy()
def save_settings(settings):
"""
将设置保存到配置文件
Args:
settings (dict): 要保存的设置字典
Returns:
bool: 保存成功返回True,否则返回False
"""
settings_path = get_settings_path()
# 确保目录存在
os.makedirs(os.path.dirname(settings_path), exist_ok=True)
try:
with open(settings_path, "w", encoding="utf-8") as f:
json.dump(settings, f, ensure_ascii=False, indent=2)
logger.info("设置已保存到文件")
return True
except Exception as e:
logger.error(f"保存设置时出错: {str(e)}")
return False
def get_settings_path():
"""
获取设置文件的路径
Returns:
str: 设置文件路径
"""
base_dir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
return os.path.join(base_dir, "config", "settings.json")