"""LEGACY config.json model -- kept only so migration.py can import an existing single-frame deployment's state into the database on first boot. Nothing else should import this module; runtime state lives in SQLite (see models.py/db.py). The file at CONFIG_PATH is deliberately never modified or deleted by the migration: it's the rollback path (redeploying the pre-database server image picks it right back up). """ from __future__ import annotations import json import os from pathlib import Path from pydantic import BaseModel CONFIG_PATH = Path(os.environ.get("CONFIG_PATH", "/data/config.json")) class FrameStats(BaseModel): first_seen: float = 0.0 device_wakes: int = 0 photos_displayed: int = 0 photos_removed: int = 0 battery_reports: int = 0 recharge_cycles: int = 0 ota_updates_applied: int = 0 config_saves: int = 0 class FrameConfig(BaseModel): immich_url: str = "" immich_api_key: str = "" management_token: str = "" album_id: str = "" order: str = "sequential" refresh_interval_s: int = 3600 quiet_hours_enabled: bool = False quiet_hours_start: str = "22:00" quiet_hours_end: str = "07:00" timezone: str = "UTC" smart_crop_faces: bool = True orientation: str = "landscape" current_asset_id: str = "" current_asset_set_at: float = 0.0 queue: list[str] = [] queue_cursor: int = 0 queue_target_len: int = 20 history: list[str] = [] excluded_asset_ids: list[str] = [] battery_percent: int = -1 battery_as_of: float = 0.0 battery_history: list = [] battery_log: list = [] last_seen: float = 0.0 device_firmware_version: str = "" device_board_variant: str = "" firmware_available_version: str = "" firmware_update_repo_url: str = "" firmware_auto_update: bool = False firmware_update_token: str = "" firmware_update_checked_at: float = 0.0 firmware_gitea_latest_version: str = "" stats: FrameStats = FrameStats() def load() -> FrameConfig: """Reads the legacy file with the same env-override behavior the old server applied on every load -- which is exactly how env-configured IMMICH_URL/IMMICH_API_KEY get baked into the database at migration time even though they were never written to the file itself.""" if not CONFIG_PATH.exists(): cfg = FrameConfig() else: cfg = FrameConfig(**json.loads(CONFIG_PATH.read_text())) env_url = os.environ.get("IMMICH_URL") env_key = os.environ.get("IMMICH_API_KEY") env_token = os.environ.get("MANAGEMENT_TOKEN") env_gitea_token = os.environ.get("GITEA_FIRMWARE_TOKEN") if env_url: cfg.immich_url = env_url if env_key: cfg.immich_api_key = env_key if env_token: cfg.management_token = env_token if env_gitea_token: cfg.firmware_update_token = env_gitea_token return cfg