from __future__ import annotations from dataclasses import dataclass from pathlib import Path import os from dotenv import load_dotenv ROOT_DIR = Path(__file__).resolve().parent.parent load_dotenv(ROOT_DIR / ".env") def _int_env(name: str, default: int) -> int: value = os.getenv(name) if not value: return default return int(value) def _bool_env(name: str, default: bool) -> bool: value = os.getenv(name) if value is None: return default return value.strip().lower() in {"1", "true", "yes", "on"} @dataclass(frozen=True) class Settings: app_id: str product_name: str database_path: Path sync_interval_minutes: int auto_sync_enabled: bool twitter_enabled: bool twitter_username: str twitter_scraper_path: Path twitter_output_dir: Path twitter_browser_provider: str twitter_full_max_no_new: int twitter_incremental_max_no_new: int twitter_thread_max_no_new: int twitter_command_timeout_seconds: int twitter_full_reply_post_limit: int twitter_incremental_reply_parent_limit: int discussion_full_scan_max_pages: int discussion_incremental_max_pages: int full_scan_time_limit_seconds: int openrouter_api_key: str | None openrouter_model: str openrouter_referer: str openrouter_title: str def get_settings() -> Settings: database_path = Path(os.getenv("DATABASE_PATH", "data/tohotopia_monitor.sqlite3")) if not database_path.is_absolute(): database_path = ROOT_DIR / database_path twitter_scraper_path = Path( os.getenv( "TWITTER_SCRAPER_PATH", str(Path.home() / ".codex" / "skills" / "social-media-scraper" / "scraper.py"), ) ) if not twitter_scraper_path.is_absolute(): twitter_scraper_path = ROOT_DIR / twitter_scraper_path twitter_output_dir = Path(os.getenv("TWITTER_OUTPUT_DIR", "任务/社媒数据/twitter-monitor")) if not twitter_output_dir.is_absolute(): twitter_output_dir = ROOT_DIR / twitter_output_dir return Settings( app_id=os.getenv("APP_ID", "3774440"), product_name=os.getenv("PRODUCT_NAME", "帝国幻想乡~TOHOTOPIA"), database_path=database_path, sync_interval_minutes=_int_env("SYNC_INTERVAL_MINUTES", 30), auto_sync_enabled=_bool_env("AUTO_SYNC_ENABLED", True), twitter_enabled=_bool_env("TWITTER_ENABLED", False), twitter_username=os.getenv("TWITTER_USERNAME", "Tohotopia"), twitter_scraper_path=twitter_scraper_path, twitter_output_dir=twitter_output_dir, twitter_browser_provider=os.getenv("TWITTER_BROWSER_PROVIDER", "existing"), twitter_full_max_no_new=_int_env("TWITTER_FULL_MAX_NO_NEW", 6), twitter_incremental_max_no_new=_int_env("TWITTER_INCREMENTAL_MAX_NO_NEW", 2), twitter_thread_max_no_new=_int_env("TWITTER_THREAD_MAX_NO_NEW", 3), twitter_command_timeout_seconds=_int_env("TWITTER_COMMAND_TIMEOUT_SECONDS", 900), twitter_full_reply_post_limit=_int_env("TWITTER_FULL_REPLY_POST_LIMIT", 0), twitter_incremental_reply_parent_limit=_int_env("TWITTER_INCREMENTAL_REPLY_PARENT_LIMIT", 20), discussion_full_scan_max_pages=_int_env("DISCUSSION_FULL_SCAN_MAX_PAGES", 500), discussion_incremental_max_pages=_int_env("DISCUSSION_INCREMENTAL_MAX_PAGES", 5), full_scan_time_limit_seconds=_int_env("FULL_SCAN_TIME_LIMIT_SECONDS", 7200), openrouter_api_key=os.getenv("OPENROUTER_API_KEY"), openrouter_model=os.getenv("OPENROUTER_MODEL", "deepseek/deepseek-v4-pro"), openrouter_referer=os.getenv("OPENROUTER_REFERER", "http://localhost:8000"), openrouter_title=os.getenv("OPENROUTER_TITLE", "TOHOTOPIA Steam Monitor"), )