Files
RFP_Infinity-Vis/Infinity_Vis_1/infinity_vis_1/presets.py

64 lines
1.9 KiB
Python

from __future__ import annotations
from dataclasses import asdict, dataclass
from datetime import datetime
from pathlib import Path
import json
import re
from .models import PatternParams, SceneState
@dataclass(slots=True)
class PresetRecord:
name: str
pattern_id: str
tempo_bpm: float
params: dict
created_at: str
@classmethod
def from_scene(cls, name: str, scene: SceneState) -> "PresetRecord":
return cls(
name=name,
pattern_id=scene.pattern_id,
tempo_bpm=scene.tempo_bpm,
params=asdict(scene.params),
created_at=datetime.utcnow().isoformat(timespec="seconds"),
)
class PresetStore:
def __init__(self, root: str | Path) -> None:
self.root = Path(root)
self.root.mkdir(parents=True, exist_ok=True)
def save(self, record: PresetRecord) -> Path:
path = self.root / f"{slugify(record.name)}.json"
path.write_text(json.dumps(asdict(record), indent=2), encoding="utf-8")
return path
def list(self) -> list[PresetRecord]:
presets: list[PresetRecord] = []
for path in sorted(self.root.glob("*.json")):
try:
payload = json.loads(path.read_text(encoding="utf-8"))
presets.append(PresetRecord(**payload))
except (OSError, json.JSONDecodeError, TypeError):
continue
return presets
def load_scene(self, name: str) -> SceneState:
path = self.root / f"{slugify(name)}.json"
payload = json.loads(path.read_text(encoding="utf-8"))
record = PresetRecord(**payload)
return SceneState(
pattern_id=record.pattern_id,
tempo_bpm=float(record.tempo_bpm),
params=PatternParams(**record.params),
)
def slugify(value: str) -> str:
return re.sub(r"[^a-z0-9]+", "-", value.lower()).strip("-") or "preset"