diff --git a/app/api/v1/plugins.py b/app/api/v1/plugins.py index 95a8712..eaae14d 100644 --- a/app/api/v1/plugins.py +++ b/app/api/v1/plugins.py @@ -207,6 +207,7 @@ async def list_plugins(current_user: dict = Depends(get_current_user)): fx_paths = set() unknown_paths = set() fx_norm_names = set() + unknown_norm_names = set() try: from app.core.vst_engine import get_plugin_manager for e in get_plugin_manager().list_scan_all(): @@ -214,8 +215,11 @@ async def list_plugins(current_user: dict = Depends(get_current_user)): if e.get("is_fx"): fx_paths.add(path) fx_norm_names.add(_norm_plugin_name(e.get("name") or "")) + fx_norm_names.add(_norm_path_stem(e.get("path") or "")) elif e.get("is_unknown"): unknown_paths.add(path) + unknown_norm_names.add(_norm_plugin_name(e.get("name") or "")) + unknown_norm_names.add(_norm_path_stem(e.get("path") or "")) except Exception: pass blocked = fx_paths | unknown_paths @@ -226,6 +230,12 @@ async def list_plugins(current_user: dict = Depends(get_current_user)): # EQ.vst3...) nhưng path .dll ≠ path .vst3 → block theo path KHÔNG trúng. # Loại theo TÊN normalized (bỏ prefix iZ, lowercase alnum) — VST2 thật # (DSK Asian DreamZ, Kong Audio...) không trùng tên FX → vẫn giữ. + # Ngoài is_fx còn loại entry UNKNOWN theo TÊN: bridge timeout khi + # introspect VST3 (vd Ozone Pro.vst3, Tonal Balance Control Pro.vst3 — + # module treo 12s → skip) nên không vào fx_norm_names, nhưng VST2 legacy + # .dll CÙNG TÊN (Ozone Pro.dll) vẫn lọt vào nút Synth → load FX như + # instrument → không ra tiếng. UNKNOWN = không xác định loại → cũng + # không hiện là instrument (cùng chính sách block theo path ở trên). name = v.get("name") or "" if name.startswith("iZ") and "izotope" in ((v.get("path") or "").lower()): # iZotope KHÔNG sản xuất VST instrument — mọi module .dll/VST2 của @@ -233,9 +243,12 @@ async def list_plugins(current_user: dict = Depends(get_current_user)): # VST2 legacy không introspect được → bridge không đánh is_fx → lọt # vào nút Synth (iZOzonePro, iZRXProMusicRebalance, iZTonalBalanceControlPro). return True - if not fx_norm_names: + if not fx_norm_names and not unknown_norm_names: return False - return _norm_plugin_name(name) in fx_norm_names + nm_name = _norm_plugin_name(name) + nm_stem = _norm_path_stem(v.get("path") or "") + return (nm_name in fx_norm_names or nm_stem in fx_norm_names + or nm_name in unknown_norm_names or nm_stem in unknown_norm_names) if blocked: avail["vst_instruments"] = [v for v in avail["vst_instruments"] @@ -269,6 +282,16 @@ def _norm_plugin_name(name: str) -> str: s = s[2:] return s +def _norm_path_stem(path: str) -> str: + """Chuẩn hóa TÊN FILE (không phần mở rộng) của path — dùng cho entry UNKNOWN + mà bridge chỉ report filename kèm đuôi ('Ozone Pro.vst3') vì timeout khi + introspect: stem 'Ozone Pro' khớp VST2 legacy 'Ozone Pro.dll' cùng tên.""" + base = os.path.basename((path or "").replace("\\", "/")) + s = "".join(ch for ch in os.path.splitext(base)[0].lower() if ch.isalnum()) + if s.startswith("iz") and len(s) > 2: + s = s[2:] + return s + def _scan_soundfonts_in_dirs(dirs: list) -> list: """Walk các thư mục (plugin_dirs user) → danh sách soundfont .sf2/.sf3 diff --git a/build_install.ps1 b/build_install.ps1 index 1eacb44..761a27e 100644 --- a/build_install.ps1 +++ b/build_install.ps1 @@ -12,23 +12,32 @@ # (VS2019/2022 + vcpkg + vst3sdk submodule + sfizz-src). Chay lai # build_windows.ps1 neu muon build lai bridge/app tu source. # LUU Y: file nay chi dung ky tu ASCII (PowerShell 5.1). -$ErrorActionPreference = "Stop" +# "Stop" + npm/pip warn tren stderr -> NativeCommandError -> chet oai. Dung +# "Continue" + kiem tra $LASTEXITCODE thu cong sau tung lenh native. +$ErrorActionPreference = "Continue" Set-Location $PSScriptRoot -Write-Host "== [1/4] Kill tien trinh cu ==" -Get-Process -Name "daw_engine","sonicforge-daw","daw_vst_bridge" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue +Write-Host "== [1/4] Kill tien trinh cu (chi install/dist, khong dong production) ==" +Get-Process -ErrorAction SilentlyContinue | Where-Object { + $_.Path -like "$PSScriptRoot\install\*" -or $_.Path -like "$PSScriptRoot\dist\daw_engine\*" +} | Stop-Process -Force -ErrorAction SilentlyContinue Start-Sleep -Milliseconds 500 Write-Host "== [2/4] Frontend bundle (app.jsx -> app.precompiled.js) ==" npm install --no-audit --no-fund +if ($LASTEXITCODE -ne 0) { Write-Host "ERROR: npm install that bai (exit $LASTEXITCODE)" -ForegroundColor Red; exit 1 } if (-not (Test-Path "node_modules\@babel\standalone")) { npm install @babel/standalone --no-audit --no-fund + if ($LASTEXITCODE -ne 0) { Write-Host "ERROR: npm install @babel/standalone that bai (exit $LASTEXITCODE)" -ForegroundColor Red; exit 1 } } node build.mjs +if ($LASTEXITCODE -ne 0) { Write-Host "ERROR: node build.mjs that bai (exit $LASTEXITCODE)" -ForegroundColor Red; exit 1 } Write-Host "== [3/4] Build daw_engine.exe (PyInstaller onedir) ==" python -m pip install -r requirements.txt pyinstaller pywin32 +if ($LASTEXITCODE -ne 0) { Write-Host "ERROR: pip install that bai (exit $LASTEXITCODE)" -ForegroundColor Red; exit 1 } pyinstaller engine.spec --clean --noconfirm +if ($LASTEXITCODE -ne 0) { Write-Host "ERROR: pyinstaller that bai (exit $LASTEXITCODE)" -ForegroundColor Red; exit 1 } if (-not (Test-Path "dist\daw_engine\daw_engine.exe")) { Write-Host "ERROR: dist\daw_engine\daw_engine.exe khong ton tai" -ForegroundColor Red exit 1 @@ -39,10 +48,25 @@ if ($LASTEXITCODE -ne 0) { exit 1 } -Write-Host "== [4/4] Copy vao install\ ==" +Write-Host "== [4/4] Verify bundle sach (khong config dev) + copy vao install\ ==" +# Ban cai phai reset ve mac dinh: KHONG duoc mang theo DB/password/secret/ +# plugin-dirs/scan-state cua dev sang may nguoi dung moi. +$devFiles = Get-ChildItem "dist\daw_engine" -Recurse -File -ErrorAction SilentlyContinue | Where-Object { + $_.Name -in @(".secret_key", "plugin_dirs.json", "sf_scan_state.json", "sf_scan_state.json.bak-root") -or + $_.Extension -eq ".db" +} +if ($devFiles) { + Write-Host "ERROR: bundle chua config dev - DUNG TAO BAN CAI:" -ForegroundColor Red + $devFiles | ForEach-Object { Write-Host " $($_.FullName)" -ForegroundColor Red } + exit 1 +} New-Item -ItemType Directory -Force "install" | Out-Null -if (Test-Path "install\daw_engine") { Remove-Item -Recurse -Force "install\daw_engine" } -Copy-Item "dist\daw_engine\*" "install\daw_engine\" -Recurse -Force +# Copy-Item wildcard tu dist\daw_engine vao install\daw_engine tao layout PHANG +# (noi dung _internal tran ra root, exe khong thay _internal -> treo luc chay). +# Robocopy /MIR mirror dung cau truc onedir (exe + _internal) + xoa file thua. +robocopy "dist\daw_engine" "install\daw_engine" /MIR /NFL /NDL /NJH /NP /R:1 /W:1 | Out-Null +if ($LASTEXITCODE -ge 8) { Write-Host "ERROR: robocopy install that bai (exit $LASTEXITCODE)" -ForegroundColor Red; exit 1 } +if (-not (Test-Path "install\daw_engine\_internal")) { Write-Host "ERROR: install\daw_engine\_internal thieu - onedir layout sai" -ForegroundColor Red; exit 1 } # 3 binary (bridge/lib/app) da commit san trong install/ - khong ghi de, # neu user da build lai bridge/app thi tu copy vao day. diff --git a/build_windows.ps1 b/build_windows.ps1 index a5f71ae..de0b5b4 100644 --- a/build_windows.ps1 +++ b/build_windows.ps1 @@ -20,7 +20,9 @@ param( [switch]$SkipNpm ) -$ErrorActionPreference = "Stop" +# "Stop" + npm/pip warn tren stderr -> NativeCommandError -> chet oai (da gap o +# build_install.ps1). Dung "Continue" + kiem tra $LASTEXITCODE sau tung lenh native. +$ErrorActionPreference = "Continue" Set-Location $PSScriptRoot $any = $Frontend -or $Bridge -or $Engine -or $Tauri @@ -34,18 +36,21 @@ $Stamp = Get-Date -Format "yyyyMMddHHmm" function Fail([string]$msg) { Write-Host "ERROR: $msg" -ForegroundColor Red; exit 1 } if ($doEngine -or $doTauri) { - Write-Host "== [0] Kill daw_engine.exe cu (neu dang chay - tranh khoa exe khi build) ==" - Get-Process -Name "daw_engine" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue + Write-Host "== [0] Kill engine cu (chi install/dist/resources, khong dong production) ==" + Get-Process -ErrorAction SilentlyContinue | Where-Object { + $_.Path -like "$PSScriptRoot\install\*" -or $_.Path -like "$PSScriptRoot\dist\daw_engine\*" -or $_.Path -like "$PSScriptRoot\src-tauri\resources\daw_engine\*" + } | Stop-Process -Force -ErrorAction SilentlyContinue Start-Sleep -Milliseconds 500 } # ---- [1] Frontend bundle + sync static ------------------------------------- if ($doFrontend) { Write-Host "== [1] Frontend bundle (app.jsx -> app.precompiled.js, cache-buster v=$Stamp) ==" - if (-not $SkipNpm) { npm install } + if (-not $SkipNpm) { npm install; if ($LASTEXITCODE -ne 0) { Fail "npm install that bai" } } if (-not (Test-Path "node_modules\@babel\standalone")) { Write-Host "Thieu @babel/standalone - dang cai them..." npm install @babel/standalone --no-audit --no-fund + if ($LASTEXITCODE -ne 0) { Fail "npm install @babel/standalone that bai" } } if (-not (Test-Path "node_modules\@babel\standalone")) { Fail "Khong cai duoc @babel/standalone. Kiem tra ket noi npm!" } node build.mjs $Stamp @@ -97,9 +102,9 @@ if ($doBridge) { if (-not $msbuild) { Fail "Khong tim thay MSBuild.exe. Cai VS Build Tools 2019/2022 (workload C++) va chay CMake native_bridge truoc." } foreach ($name in @("daw_vst_bridge", "fx_vst_bridge", "plugin_host")) { - $proj = "native_bridge\build\$name.vcxproj" - $exe = "native_bridge\build\Release\$name.exe" - if (-not (Test-Path $proj)) { Fail "Thieu project: $proj (can CMake native_bridge truoc)" } + $proj = "native_bridge\build\bridge-win\$name.vcxproj" + $exe = "native_bridge\build\bridge-win\Release\$name.exe" + if (-not (Test-Path $proj)) { Fail "Thieu project: $proj (can CMake native_bridge truoc - xem native_bridge/build/bridge-win)" } $newest = Get-ChildItem -Path "native_bridge\src","native_bridge\include" -Recurse -Include *.cpp,*.h,*.hpp -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 1 $needBuild = $true @@ -137,10 +142,20 @@ if ($doEngine) { if ($LASTEXITCODE -ne 0) { Fail "pyinstaller that bai" } python tools\verify_bundle.py if ($LASTEXITCODE -ne 0) { Fail "Bundle thieu asset - dung build, kiem tra engine.spec datas" } + # Ban cai phai SACH: khong duoc mang theo DB/password/secret/scan-state cua dev. + $devFiles = Get-ChildItem "dist\daw_engine" -Recurse -File -ErrorAction SilentlyContinue | Where-Object { + $_.Name -in @(".secret_key", "plugin_dirs.json", "sf_scan_state.json", "sf_scan_state.json.bak-root") -or + $_.Extension -eq ".db" + } + if ($devFiles) { + $devFiles | ForEach-Object { Write-Host " DEV-CONFIG: $($_.FullName)" -ForegroundColor Red } + Fail "Bundle chua config dev - DUNG TAO BAN CAI" + } if (-not (Test-Path "dist\daw_engine\daw_engine.exe")) { Fail "dist\daw_engine\daw_engine.exe khong ton tai (onedir build loi?)" } - if (Test-Path "src-tauri\resources\daw_engine") { Remove-Item -Recurse -Force "src-tauri\resources\daw_engine" } - New-Item -ItemType Directory -Force "src-tauri\resources\daw_engine" | Out-Null - Copy-Item "dist\daw_engine\*" "src-tauri\resources\daw_engine\" -Recurse -Force + # Robocopy /MIR (khong Copy-Item wildcard): giu dung cau truc onedir exe+_internal. + robocopy "dist\daw_engine" "src-tauri\resources\daw_engine" /MIR /NFL /NDL /NJH /NP /R:1 /W:1 | Out-Null + if ($LASTEXITCODE -ge 8) { Fail "robocopy resources that bai (exit $LASTEXITCODE)" } + if (-not (Test-Path "src-tauri\resources\daw_engine\_internal")) { Fail "resources/daw_engine/_internal thieu - onedir layout sai" } Write-Host "Engine OK -> src-tauri/resources/daw_engine" } @@ -157,7 +172,7 @@ if ($doTauri) { foreach ($name in @("daw_vst_bridge", "fx_vst_bridge", "plugin_host")) { if (-not (Test-Path "src-tauri\binaries\$name-x86_64-pc-windows-msvc.exe")) { Fail "Thieu src-tauri\binaries\$name-x86_64-pc-windows-msvc.exe - chay -Bridge truoc" } } - if (-not $SkipNpm) { npm install -D @tauri-apps/cli } + if (-not $SkipNpm) { npm install -D @tauri-apps/cli; if ($LASTEXITCODE -ne 0) { Fail "npm install @tauri-apps/cli that bai" } } npx tauri build if ($LASTEXITCODE -ne 0) { Fail "tauri build that bai" } } diff --git a/engine.spec b/engine.spec index 4a27a72..0f8c36b 100644 --- a/engine.spec +++ b/engine.spec @@ -42,7 +42,13 @@ if _SPEC_ROOT not in _sys.path: # Assets cua app: bundle QUA IMPORT SYSTEM (collect_data_files) — an toan nhat. # Loai tru storage (57MB soundfonts/uploads — vo ich, config.py da chuyen # storage sang %APPDATA%\\SonicForgeDAW khi frozen) va __pycache__. -datas = collect_data_files('app', excludes=['**/storage/**', '**/__pycache__/**', '**/*.pyc']) +# LOAI CA DEV CONFIG O app/ ROOT: bundle cai dat phai SAC — khong duoc mang +# theo DB/password/secret/scan-state cua dev sang may nguoi dung moi. +datas = collect_data_files('app', excludes=[ + '**/storage/**', '**/__pycache__/**', '**/*.pyc', + '**/*.db', '**/.secret_key', '**/plugin_dirs.json', '**/sf_scan_state.json', + '**/*.bak-root', +]) # Fallback cuoi cung: neu collect_data_files van tra ve rong (phong moi truong # hop ky la), dung datas TINH absolute — tinh huong xau nhat van co du assets. if not datas: