FEAT: Plugins Manager - danh sach thu muc da muc (Add Directory + x xoa), scan phan loai rieng re VST/SoundFont theo dir
- Backend: plugin_dirs (list) thay vst_dir/soundfont_dir rieng — luu plugin_dirs.json, backward compat gop field cu; scan walk tung dir phan loai .vst3/.dll/.so -> vst_found, .sf2/.sf3 -> soundfonts (kem dir goc) - SoundFontAutoScanner: system_sf_dirs (list) — scan tat ca thu muc user khai bao - Frontend: PluginManagerModal — nut Add Directory (Tauri dialog / prompt fallback), moi dir co nut x xoa, nut Scan -> hien danh sach rieng re VST Instruments + SoundFonts (kem duong dan thu muc) - Tests: +2 (save/get/scan phan loai, xoa dir)
This commit is contained in:
+56
-23
@@ -38,18 +38,35 @@ def _save_plugin_dirs(dirs: dict):
|
||||
json.dump(dirs, f, indent=2)
|
||||
|
||||
def _effective_dirs() -> dict:
|
||||
"""Env/.env (Docker) là base; user dirs (file) override nếu khai báo."""
|
||||
"""Env/.env (Docker) là base; user dirs (file) override nếu khai báo.
|
||||
|
||||
plugin_dirs: list thư mục user thêm trong Plugins Manager (mỗi thư mục
|
||||
có thể chứa cả VST lẫn SoundFont — scan tự phân loại). Nếu user chưa
|
||||
khai báo → fallback env VST_DIR + SOUNDFONT_DIR.
|
||||
"""
|
||||
user = _load_plugin_dirs()
|
||||
plugin_dirs = [d for d in (user.get("plugin_dirs") or []) if d]
|
||||
vst_dir = settings.VST_DIR
|
||||
soundfont_dir = settings.SOUNDFONT_DIR
|
||||
# Backward compat: file cũ lưu vst_dir/soundfont_dir riêng → gộp vào list.
|
||||
if not plugin_dirs:
|
||||
if user.get("vst_dir"):
|
||||
plugin_dirs.append(user["vst_dir"])
|
||||
if user.get("soundfont_dir"):
|
||||
plugin_dirs.append(user["soundfont_dir"])
|
||||
if not plugin_dirs:
|
||||
plugin_dirs = [vst_dir, soundfont_dir]
|
||||
return {
|
||||
"vst_dir": user.get("vst_dir") or settings.VST_DIR,
|
||||
"soundfont_dir": user.get("soundfont_dir") or settings.SOUNDFONT_DIR,
|
||||
"vst_dir_user_set": bool(user.get("vst_dir")),
|
||||
"soundfont_dir_user_set": bool(user.get("soundfont_dir")),
|
||||
"plugin_dirs": plugin_dirs,
|
||||
"vst_dir": vst_dir,
|
||||
"soundfont_dir": soundfont_dir,
|
||||
"plugin_dirs_user_set": bool(user.get("plugin_dirs")),
|
||||
}
|
||||
|
||||
class DirsRequest(BaseModel):
|
||||
vst_dir: Optional[str] = None
|
||||
soundfont_dir: Optional[str] = None
|
||||
plugin_dirs: Optional[list] = None
|
||||
|
||||
@router.get("/dirs")
|
||||
async def get_plugin_dirs():
|
||||
@@ -59,10 +76,16 @@ async def get_plugin_dirs():
|
||||
async def save_plugin_dirs(req: DirsRequest, current_user: dict = Depends(get_current_user)):
|
||||
enforce_password_changed(current_user)
|
||||
user = _load_plugin_dirs()
|
||||
if req.vst_dir is not None:
|
||||
user["vst_dir"] = req.vst_dir.strip()
|
||||
if req.soundfont_dir is not None:
|
||||
user["soundfont_dir"] = req.soundfont_dir.strip()
|
||||
if req.plugin_dirs is not None:
|
||||
user["plugin_dirs"] = [d.strip() for d in req.plugin_dirs if d and d.strip()]
|
||||
# Xóa field cũ (đã gộp vào plugin_dirs) tránh nhầm lẫn
|
||||
user.pop("vst_dir", None)
|
||||
user.pop("soundfont_dir", None)
|
||||
else:
|
||||
if req.vst_dir is not None:
|
||||
user["vst_dir"] = req.vst_dir.strip()
|
||||
if req.soundfont_dir is not None:
|
||||
user["soundfont_dir"] = req.soundfont_dir.strip()
|
||||
_save_plugin_dirs(user)
|
||||
return {"success": True, **(_effective_dirs())}
|
||||
|
||||
@@ -70,34 +93,43 @@ async def save_plugin_dirs(req: DirsRequest, current_user: dict = Depends(get_cu
|
||||
async def scan_plugin_dirs(background_tasks: BackgroundTasks = None,
|
||||
current_user: dict = Depends(get_current_user)):
|
||||
"""Scan các dir hiệu lực (env + user override): cập nhật catalog
|
||||
soundfont (inspector/scanner) + liệt kê VST. Trả về số lượng tìm thấy."""
|
||||
soundfont (inspector/scanner) + liệt kê VST. Trả về danh sách riêng rẽ
|
||||
VST (vst_found) + SoundFont (soundfonts) theo từng thư mục user khai báo."""
|
||||
enforce_password_changed(current_user)
|
||||
dirs = _effective_dirs()
|
||||
vst_dir = dirs["vst_dir"]
|
||||
sf_dir = dirs["soundfont_dir"]
|
||||
plugin_dirs = dirs["plugin_dirs"]
|
||||
# SoundFont: quét + inspect vào catalog (scan_once dùng dir hiệu lực)
|
||||
scanner = SoundFontAutoScanner(system_sf_dir=sf_dir, upload_sf_dir=UPLOAD_SF_DIR)
|
||||
scanner = SoundFontAutoScanner(system_sf_dirs=plugin_dirs, upload_sf_dir=UPLOAD_SF_DIR)
|
||||
if background_tasks:
|
||||
background_tasks.add_task(scanner.scan_once)
|
||||
else:
|
||||
scanner.scan_once()
|
||||
catalog = scanner.get_catalog()
|
||||
# VST: liệt kê thư mục (walk .vst3/.so)
|
||||
# VST + SoundFont: walk từng thư mục, phân loại riêng rẽ theo extension
|
||||
vst_found = []
|
||||
if os.path.isdir(vst_dir):
|
||||
for root, _dirs, files in os.walk(vst_dir):
|
||||
sf_found = []
|
||||
for d in plugin_dirs:
|
||||
if not os.path.isdir(d):
|
||||
continue
|
||||
for root, _dirs, files in os.walk(d):
|
||||
for f in files:
|
||||
if f.endswith(".vst3") or f.endswith(".so") or f.endswith(".dll"):
|
||||
low = f.lower()
|
||||
if low.endswith(".vst3") or low.endswith(".dll") or low.endswith(".so"):
|
||||
vst_found.append({"name": os.path.splitext(f)[0],
|
||||
"path": os.path.join(root, f),
|
||||
"type": "VST3" if f.endswith(".vst3") else "VST2"})
|
||||
"dir": d,
|
||||
"type": "VST3" if low.endswith(".vst3") else "VST2"})
|
||||
elif low.endswith(".sf2") or low.endswith(".sf3"):
|
||||
sf_found.append({"name": os.path.splitext(f)[0],
|
||||
"path": os.path.join(root, f),
|
||||
"dir": d})
|
||||
return {
|
||||
"success": True,
|
||||
"vst_dir": vst_dir,
|
||||
"soundfont_dir": sf_dir,
|
||||
"plugin_dirs": plugin_dirs,
|
||||
"vst_found": vst_found,
|
||||
"vst_count": len(vst_found),
|
||||
"soundfont_count": len(catalog),
|
||||
"soundfonts": sf_found,
|
||||
"soundfont_count": len(sf_found),
|
||||
}
|
||||
|
||||
_inspector = None
|
||||
@@ -107,14 +139,15 @@ def get_inspector():
|
||||
global _inspector
|
||||
if _inspector is None:
|
||||
d = _effective_dirs()
|
||||
_inspector = SoundFontInspector(system_sf_dir=d["soundfont_dir"], upload_sf_dir=UPLOAD_SF_DIR)
|
||||
_inspector = SoundFontInspector(d["plugin_dirs"][0] if d["plugin_dirs"] else settings.SOUNDFONT_DIR,
|
||||
upload_sf_dir=UPLOAD_SF_DIR)
|
||||
return _inspector
|
||||
|
||||
def get_scanner():
|
||||
global _scanner
|
||||
if _scanner is None:
|
||||
d = _effective_dirs()
|
||||
_scanner = SoundFontAutoScanner(system_sf_dir=d["soundfont_dir"], upload_sf_dir=UPLOAD_SF_DIR)
|
||||
_scanner = SoundFontAutoScanner(system_sf_dirs=d["plugin_dirs"], upload_sf_dir=UPLOAD_SF_DIR)
|
||||
_scanner.scan_once()
|
||||
return _scanner
|
||||
|
||||
|
||||
Reference in New Issue
Block a user