72 lines
2.1 KiB
Python
72 lines
2.1 KiB
Python
"""Blenderに依存しないSEライブラリの走査・設定処理。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
|
|
|
|
AUDIO_EXTENSIONS = {".mp3", ".wav", ".flac", ".ogg", ".m4a", ".aac"}
|
|
CONFIG_FILENAME = ".se_palette.json"
|
|
|
|
|
|
def scan_audio_files(folder: str) -> list[Path]:
|
|
"""フォルダ直下の対応音声ファイルを名前順で返す。"""
|
|
root = Path(folder).expanduser()
|
|
if not root.is_dir():
|
|
return []
|
|
return sorted(
|
|
(
|
|
path
|
|
for path in root.iterdir()
|
|
if path.is_file() and path.suffix.lower() in AUDIO_EXTENSIONS
|
|
),
|
|
key=lambda path: path.name.casefold(),
|
|
)
|
|
|
|
|
|
def default_label(path: Path) -> str:
|
|
"""拡張子と管理用の先頭番号を除いた表示名を作る。"""
|
|
label = path.stem
|
|
if len(label) > 3 and label[:2].isdigit() and label[2] in {"_", "-", " "}:
|
|
label = label[3:]
|
|
return label.replace("_", " ")
|
|
|
|
|
|
def load_config(folder: str) -> dict:
|
|
config_path = Path(folder).expanduser() / CONFIG_FILENAME
|
|
if not config_path.is_file():
|
|
return {"items": {}}
|
|
try:
|
|
data = json.loads(config_path.read_text(encoding="utf-8"))
|
|
except (OSError, json.JSONDecodeError):
|
|
return {"items": {}}
|
|
if not isinstance(data, dict) or not isinstance(data.get("items", {}), dict):
|
|
return {"items": {}}
|
|
return data
|
|
|
|
|
|
def save_config(folder: str, items: list[dict]) -> Path:
|
|
root = Path(folder).expanduser()
|
|
root.mkdir(parents=True, exist_ok=True)
|
|
config_path = root / CONFIG_FILENAME
|
|
payload = {
|
|
"version": 1,
|
|
"items": {
|
|
item["filename"]: {
|
|
"label": item.get("label", ""),
|
|
"icon": item.get("icon", "PLAY_SOUND"),
|
|
"icon_path": item.get("icon_path", ""),
|
|
}
|
|
for item in items
|
|
},
|
|
}
|
|
temporary_path = config_path.with_suffix(config_path.suffix + ".tmp")
|
|
temporary_path.write_text(
|
|
json.dumps(payload, ensure_ascii=False, indent=2) + "\n",
|
|
encoding="utf-8",
|
|
)
|
|
os.replace(temporary_path, config_path)
|
|
return config_path
|