87 lines
3.4 KiB
Python
87 lines
3.4 KiB
Python
import os
|
|
import platform
|
|
import logging
|
|
from typing import List, Dict, Any
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class NativePluginScanner:
|
|
"""Quét thư mục custom chứa VST3 (.vst3) / Audio Unit (.component trên macOS)
|
|
— spec DESKTOP VST (2026-08-08): POST /api/v1/desktop/plugins/scan."""
|
|
|
|
def __init__(self):
|
|
self.os_type = platform.system() # 'Linux', 'Windows', 'Darwin'
|
|
|
|
def scan_directories(self, target_paths: List[str]) -> List[Dict[str, Any]]:
|
|
found_plugins = []
|
|
seen = set()
|
|
|
|
for base_path in target_paths:
|
|
if not base_path:
|
|
continue
|
|
if not os.path.exists(base_path):
|
|
logger.warning(f"Scan path does not exist: {base_path}")
|
|
continue
|
|
|
|
for root, dirs, files in os.walk(base_path):
|
|
for dir_name in dirs:
|
|
full_path = os.path.join(root, dir_name)
|
|
|
|
# VST3 = bundle directory *.vst3
|
|
if dir_name.endswith('.vst3'):
|
|
plugin_name = dir_name[:-5]
|
|
pid = f"vst3_{plugin_name.lower().replace(' ', '_')}"
|
|
if pid in seen:
|
|
continue
|
|
seen.add(pid)
|
|
found_plugins.append({
|
|
"id": pid,
|
|
"name": plugin_name,
|
|
"type": "VST3",
|
|
"format": "VST3",
|
|
"category": "Instrument",
|
|
"vendor": self._read_vendor(full_path) or None,
|
|
"path": full_path,
|
|
"is_instrument": True,
|
|
"has_native_gui": True
|
|
})
|
|
# Audio Unit = bundle *.component (macOS only)
|
|
elif dir_name.endswith('.component') and self.os_type == 'Darwin':
|
|
plugin_name = dir_name[:-10]
|
|
pid = f"au_{plugin_name.lower().replace(' ', '_')}"
|
|
if pid in seen:
|
|
continue
|
|
seen.add(pid)
|
|
found_plugins.append({
|
|
"id": pid,
|
|
"name": plugin_name,
|
|
"type": "AU",
|
|
"format": "AudioUnit",
|
|
"category": "Instrument",
|
|
"vendor": self._read_vendor(full_path) or None,
|
|
"path": full_path,
|
|
"is_instrument": True,
|
|
"has_native_gui": True
|
|
})
|
|
|
|
return found_plugins
|
|
|
|
@staticmethod
|
|
def _read_vendor(bundle_path: str) -> str:
|
|
"""Đọc vendor từ Info.plist nếu có (macOS) — best-effort."""
|
|
try:
|
|
plist = os.path.join(bundle_path, "Contents", "Info.plist")
|
|
if os.path.exists(plist):
|
|
with open(plist, "rb") as f:
|
|
raw = f.read(65536)
|
|
import plistlib
|
|
try:
|
|
data = plistlib.loads(raw)
|
|
return data.get("CFBundleManufacturer") or data.get("NSHumanReadableCopyright")
|
|
except Exception:
|
|
return None
|
|
except Exception:
|
|
return None
|
|
return None
|