refactor: scenes now folder-based with preview image support
This commit is contained in:
+47
-17
@@ -84,34 +84,51 @@ class SceneManager:
|
||||
|
||||
def list_all(self, game_id: str | None = None) -> list[dict[str, Any]]:
|
||||
scenes = []
|
||||
for f in SCENES_DIR.glob("*.json"):
|
||||
for item in SCENES_DIR.iterdir():
|
||||
if not item.is_dir():
|
||||
continue
|
||||
f = item / "scene.json"
|
||||
if not f.exists():
|
||||
continue
|
||||
try:
|
||||
with open(f, "r", encoding="utf-8") as fp:
|
||||
data = json.load(fp)
|
||||
scene = Scene.from_dict(data)
|
||||
if game_id is None or scene.game_id == game_id:
|
||||
scenes.append(scene.to_dict())
|
||||
d = scene.to_dict()
|
||||
for ext in ["jpg","jpeg","png","webp","gif"]:
|
||||
if (item / f"preview.{ext}").exists():
|
||||
d["preview_ext"] = ext
|
||||
break
|
||||
scenes.append(d)
|
||||
except Exception as e:
|
||||
logger.error("Failed to load scene %s: %s", f.name, e)
|
||||
logger.error("Failed to load scene %s: %s", item.name, e)
|
||||
return scenes
|
||||
|
||||
def get(self, scene_id: str) -> dict[str, Any] | None:
|
||||
filepath = SCENES_DIR / f"{scene_id}.json"
|
||||
if not filepath.exists():
|
||||
item = SCENES_DIR / scene_id
|
||||
f = item / "scene.json"
|
||||
if not f.exists():
|
||||
return None
|
||||
try:
|
||||
with open(filepath, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
return Scene.from_dict(data).to_dict()
|
||||
with open(f, "r", encoding="utf-8") as fp:
|
||||
data = json.load(fp)
|
||||
d = Scene.from_dict(data).to_dict()
|
||||
for ext in ["jpg","jpeg","png","webp","gif"]:
|
||||
if (item / f"preview.{ext}").exists():
|
||||
d["preview_ext"] = ext
|
||||
break
|
||||
return d
|
||||
except Exception as e:
|
||||
logger.error("Failed to read scene %s: %s", scene_id, e)
|
||||
return None
|
||||
|
||||
def save(self, scene: Scene) -> bool:
|
||||
scene.updated_at = datetime.now().isoformat()
|
||||
filepath = SCENES_DIR / f"{scene.id}.json"
|
||||
item = SCENES_DIR / scene.id
|
||||
item.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
with open(filepath, "w", encoding="utf-8") as f:
|
||||
with open(item / "scene.json", "w", encoding="utf-8") as f:
|
||||
json.dump(scene.to_dict(), f, indent=2, ensure_ascii=False)
|
||||
logger.info("Scene saved: %s", scene.id)
|
||||
return True
|
||||
@@ -120,20 +137,23 @@ class SceneManager:
|
||||
return False
|
||||
|
||||
def delete(self, scene_id: str) -> bool:
|
||||
filepath = SCENES_DIR / f"{scene_id}.json"
|
||||
if filepath.exists():
|
||||
filepath.unlink()
|
||||
import shutil
|
||||
item = SCENES_DIR / scene_id
|
||||
if item.exists():
|
||||
shutil.rmtree(item)
|
||||
logger.info("Scene deleted: %s", scene_id)
|
||||
return True
|
||||
return False
|
||||
|
||||
def export_scene_zip(self, scene_id: str) -> bytes | None:
|
||||
filepath = SCENES_DIR / f"{scene_id}.json"
|
||||
if not filepath.exists():
|
||||
item = SCENES_DIR / scene_id
|
||||
if not item.exists():
|
||||
return None
|
||||
buf = io.BytesIO()
|
||||
with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as zf:
|
||||
zf.write(filepath, "scene.json")
|
||||
for f in sorted(item.rglob("*")):
|
||||
if f.is_file():
|
||||
zf.write(f, f.relative_to(item))
|
||||
logger.info("Scene exported as zip: %s", scene_id)
|
||||
return buf.getvalue()
|
||||
|
||||
@@ -145,7 +165,17 @@ class SceneManager:
|
||||
return False
|
||||
data = json.loads(zf.read("scene.json").decode('utf-8'))
|
||||
scene = Scene.from_dict(data)
|
||||
return self.save(scene)
|
||||
item = SCENES_DIR / scene.id
|
||||
if item.exists():
|
||||
import shutil; shutil.rmtree(item)
|
||||
item.mkdir(parents=True)
|
||||
for name in zf.namelist():
|
||||
if name.endswith('/'): continue
|
||||
dest = item / name
|
||||
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||
dest.write_bytes(zf.read(name))
|
||||
logger.info("Scene imported from zip: %s", scene.id)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error("Failed to import scene zip: %s", e)
|
||||
return False
|
||||
|
||||
Reference in New Issue
Block a user