repository_config_snapshot.py 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #!/usr/bin/env python3
  2. """仓库根 ``config.ini`` 与 ``save/project-config`` 的一次性快照。"""
  3. from __future__ import annotations
  4. import configparser
  5. import json
  6. import sys
  7. from dataclasses import dataclass
  8. from pathlib import Path
  9. from typing import Any
  10. _SINGLETON_MODULE_SOURCE_FILE_PATH = Path(__file__).resolve()
  11. REPOSITORY_ROOT_DIRECTORY: Path = _SINGLETON_MODULE_SOURCE_FILE_PATH.parent.parent
  12. _repository_root_directory_string = str(REPOSITORY_ROOT_DIRECTORY)
  13. if _repository_root_directory_string not in sys.path:
  14. sys.path.insert(0, _repository_root_directory_string)
  15. _CONFIG_INI_FILE_PATH = REPOSITORY_ROOT_DIRECTORY / "config.ini"
  16. _PROJECT_CONFIG_PRIMARY_FILE_PATH = REPOSITORY_ROOT_DIRECTORY / "save" / "project-config"
  17. _PROJECT_CONFIG_LEGACY_FILE_PATH = REPOSITORY_ROOT_DIRECTORY / "save" / "input-keyword.config"
  18. @dataclass(frozen=True)
  19. class PyAutoGUIScreenCalibration:
  20. viewport_to_screen_scale_x: float = 1.0
  21. viewport_to_screen_scale_y: float = 1.0
  22. screen_offset_x: int = 0
  23. screen_offset_y: int = 0
  24. @dataclass(frozen=True)
  25. class RepositoryConfigIniSnapshot:
  26. home_page_url: str
  27. python_executable_relative_path: str
  28. pyautogui_screen_calibration: PyAutoGUIScreenCalibration
  29. project_config: dict[str, Any]
  30. _REPOSITORY_CONFIG_INI_SNAPSHOT_SINGLETON: RepositoryConfigIniSnapshot | None = None
  31. def _read_project_config_mapping_from_repository_save_directory() -> dict[str, Any]:
  32. if _PROJECT_CONFIG_PRIMARY_FILE_PATH.is_file():
  33. raw_text = _PROJECT_CONFIG_PRIMARY_FILE_PATH.read_text(encoding="utf-8")
  34. parsed_object = json.loads(raw_text)
  35. return parsed_object if isinstance(parsed_object, dict) else {}
  36. if _PROJECT_CONFIG_LEGACY_FILE_PATH.is_file():
  37. raw_text = _PROJECT_CONFIG_LEGACY_FILE_PATH.read_text(encoding="utf-8")
  38. parsed_object = json.loads(raw_text)
  39. return parsed_object if isinstance(parsed_object, dict) else {}
  40. return {}
  41. def _read_repository_config_ini_snapshot_from_disk() -> RepositoryConfigIniSnapshot:
  42. parser = configparser.ConfigParser()
  43. parser.read(_CONFIG_INI_FILE_PATH, encoding="utf-8")
  44. python_executable_relative_path = parser.get(
  45. "paths",
  46. "pythonRelative",
  47. fallback="python/py/python.exe",
  48. )
  49. home_page_url = parser.get(
  50. "urls",
  51. "homeUrl",
  52. fallback="https://www.xiaohongshu.com/",
  53. )
  54. pyautogui_screen_calibration = PyAutoGUIScreenCalibration()
  55. project_config_mapping = _read_project_config_mapping_from_repository_save_directory()
  56. return RepositoryConfigIniSnapshot(
  57. home_page_url=home_page_url.strip(),
  58. python_executable_relative_path=python_executable_relative_path.strip(),
  59. pyautogui_screen_calibration=pyautogui_screen_calibration,
  60. project_config=project_config_mapping,
  61. )
  62. def get_repository_config_ini_snapshot() -> RepositoryConfigIniSnapshot:
  63. global _REPOSITORY_CONFIG_INI_SNAPSHOT_SINGLETON
  64. if _REPOSITORY_CONFIG_INI_SNAPSHOT_SINGLETON is None:
  65. _REPOSITORY_CONFIG_INI_SNAPSHOT_SINGLETON = (
  66. _read_repository_config_ini_snapshot_from_disk()
  67. )
  68. return _REPOSITORY_CONFIG_INI_SNAPSHOT_SINGLETON
  69. __all__ = [
  70. "PyAutoGUIScreenCalibration",
  71. "RepositoryConfigIniSnapshot",
  72. "REPOSITORY_ROOT_DIRECTORY",
  73. "get_repository_config_ini_snapshot",
  74. ]