Files
telegram-scraper/app_state.py
T

85 lines
2.8 KiB
Python

import json
import threading
from pathlib import Path
from typing import Any, Callable, Dict
DEFAULT_STATE: Dict[str, Any] = {
"api_id": None,
"api_hash": None,
"channels": {},
"channel_names": {},
"scrape_media": True,
"forwarding_rules": [],
"continuous_scraping": {
"enabled": True,
"interval_minutes": 1,
"channels": [],
"run_all_tracked": True,
},
}
class StateStore:
def __init__(self, path: Path):
self.path = path
self.lock = threading.RLock()
def load(self) -> Dict[str, Any]:
with self.lock:
if not self.path.exists():
return self._default_state()
try:
with self.path.open("r", encoding="utf-8") as handle:
state = json.load(handle)
except (json.JSONDecodeError, OSError):
return self._default_state()
return self._merge_defaults(state)
def save(self, state: Dict[str, Any]) -> None:
with self.lock:
self.path.parent.mkdir(parents=True, exist_ok=True)
tmp_path = self.path.with_suffix(self.path.suffix + ".tmp")
with tmp_path.open("w", encoding="utf-8") as handle:
json.dump(self._merge_defaults(state), handle, ensure_ascii=False, indent=2)
handle.write("\n")
tmp_path.replace(self.path)
def update(self, mutator: Callable[[Dict[str, Any]], None]) -> Dict[str, Any]:
with self.lock:
state = self.load()
mutator(state)
self.save(state)
return state
def continuous_config(self) -> Dict[str, Any]:
state = self.load()
return dict(state.get("continuous_scraping") or DEFAULT_STATE["continuous_scraping"])
def save_continuous_config(self, config: Dict[str, Any]) -> Dict[str, Any]:
def mutate(state: Dict[str, Any]) -> None:
state["continuous_scraping"] = {
"enabled": bool(config.get("enabled", True)),
"interval_minutes": max(1, int(config.get("interval_minutes", 1) or 1)),
"channels": [
str(item).strip()
for item in config.get("channels", [])
if str(item).strip()
],
"run_all_tracked": bool(config.get("run_all_tracked", True)),
}
return self.update(mutate)["continuous_scraping"]
def _default_state(self) -> Dict[str, Any]:
return json.loads(json.dumps(DEFAULT_STATE))
def _merge_defaults(self, state: Dict[str, Any]) -> Dict[str, Any]:
merged = self._default_state()
for key, value in state.items():
if key == "continuous_scraping" and isinstance(value, dict):
merged[key].update(value)
else:
merged[key] = value
return merged