FEAT: cài đặt các thư viện để chuẩn bị build exe trên window

This commit is contained in:
2026-08-08 08:46:15 +07:00
parent 9ef622f29a
commit 029ed1c456
24 changed files with 575 additions and 13 deletions
+86 -6
View File
@@ -14193,6 +14193,12 @@ const App = () => {
const [selectedSoundFontId, setSelectedSoundFontId] = useState(null);
const [sfPresets, setSfPresets] = useState(null); // presets from SoundFont
const [instrumentDropdownTrackId, setInstrumentDropdownTrackId] = useState(null);
// Plugin Manager VST scan (spec desktop 2026-08-08)
const [vstScanOpen, setVstScanOpen] = useState(false);
const [vstScanPath, setVstScanPath] = useState('/opt/daw_engine/vst3');
const [vstScanning, setVstScanning] = useState(false);
const [vstPlugins, setVstPlugins] = useState([]);
const [vstScanError, setVstScanError] = useState(null);
const [instrumentDropdownBtnRect, setInstrumentDropdownBtnRect] = useState(null);
const [instrumentSearchQuery, setInstrumentSearchQuery] = useState('');
const [sfPresetSearchQuery, setSfPresetSearchQuery] = useState('');
@@ -14249,8 +14255,9 @@ const App = () => {
"Tinkle Bell","Agogo","Steel Drums","Woodblock","Taiko Drum","Melodic Tom","Synth Drum","Reverse Cymbal",
"Guitar Fret Noise","Breath Noise","Seashore","Bird Tweet","Telephone Ring","Helicopter","Applause","Gunshot"
];
const setTrackInstrumentWithProgram = (trackId, instrumentId, programNumber, displayName, bankNumber) => {
const setTrackInstrumentWithProgram = (trackId, instrumentId, programNumber, displayName, bankNumber, vstMeta) => {
const isSfInstrument = instrumentId && typeof instrumentId === 'string' && instrumentId.startsWith('sf_');
const isVstInstrument = instrumentId && typeof instrumentId === 'string' && (instrumentId.startsWith('vst3_') || instrumentId.startsWith('au_') || (vstMeta && vstMeta.format));
const sfBank = bankNumber !== undefined ? bankNumber : (isSfInstrument ? 0 : undefined);
const sfProg = programNumber !== undefined ? programNumber : undefined;
var mt = activeTracksRef.current || tracks;
@@ -14264,6 +14271,12 @@ const App = () => {
const synthEngine = hasInstrument ? {
type: instrType,
plugin_id: instrumentId,
// spec desktop 2026-08-08: synth_engine đy đ {type, plugin_id, plugin_name, format, plugin_path}
...(isVstInstrument ? {
plugin_name: (vstMeta && vstMeta.plugin_name) || (displayName || instrumentId).replace(/\s*\((VST3|AU|AudioUnit)\)\s*$/, ''),
format: (vstMeta && vstMeta.format) || (instrumentId.startsWith('au_') ? 'AudioUnit' : 'VST3'),
plugin_path: (vstMeta && vstMeta.plugin_path) || ''
} : {}),
soundfont_bank: sfBank !== undefined ? sfBank : 0,
soundfont_program: sfProg !== undefined ? sfProg : 0,
soundfont_id: isSfInstrument ? instrumentId.replace('sf_', '') : ''
@@ -15114,7 +15127,7 @@ const App = () => {
setAiPrompt(newText);
};
const setTrackInstrumentWithUndo = (trackId, instrumentId, displayName, bankNumber, programNumber) => {
const setTrackInstrumentWithUndo = (trackId, instrumentId, displayName, bankNumber, programNumber, vstMeta) => {
const track = activeTracks.find(t => t.id === trackId);
if (!track) return;
const oldInstrumentId = track.instrumentId;
@@ -15136,7 +15149,7 @@ const App = () => {
}
};
if (window.UndoRedoEngine) window.UndoRedoEngine.execute(entry);
setTrackInstrumentWithProgram(trackId, instrumentId, programNumber, displayName, bankNumber);
setTrackInstrumentWithProgram(trackId, instrumentId, programNumber, displayName, bankNumber, vstMeta);
};
const createSectionWithUndo = (trackId, section) => {
@@ -29370,11 +29383,78 @@ STRICT CONSTRAINTS:
filteredInstruments.vst.length > 0 && /*#__PURE__*/React.createElement("div", { className: "text-[10px] text-zinc-500 px-3 py-1 mt-1 uppercase font-bold" }, "VST Instruments"),
filteredInstruments.vst.map((v, i) => /*#__PURE__*/React.createElement("button", {
key: "vstd_" + i,
onClick: () => { setInstrumentDropdownTrackId(null); setInstrumentDropdownBtnRect(null); setTrackInstrumentWithUndo(instrumentDropdownTrackId, v.id, v.name || v.id); },
onClick: () => { setInstrumentDropdownTrackId(null); setInstrumentDropdownBtnRect(null); setTrackInstrumentWithUndo(instrumentDropdownTrackId, v.id, v.name || v.id, undefined, undefined, { plugin_name: v.name || v.id, format: v.type || 'VST3', plugin_path: v.path || '' }); },
className: "w-full text-left px-3 py-1.5 text-xs bg-zinc-800 hover:bg-violet-800 text-zinc-200 flex items-center justify-between"
}, /*#__PURE__*/React.createElement("span", { className: "truncate" }, v.name || v.id), /*#__PURE__*/React.createElement("span", { className: "text-[10px] text-cyan-400 shrink-0 ml-1" }, v.type || "VST"))),
(!filteredInstruments.soundfonts.length && !filteredInstruments.vst.length) && /*#__PURE__*/React.createElement("p", { className: "text-xs text-zinc-500 py-4 text-center" }, "Kh\u00f4ng t\u00ecm th\u1ea5y nh\u1ea1c c\u1ee5 n\u00e0o")
)));
/*#__PURE__*/React.createElement("button", {
onClick: () => { setInstrumentDropdownBtnRect(null); setVstScanOpen(true); },
className: "w-full text-left px-3 py-1.5 text-xs bg-purple-900/40 hover:bg-purple-800/60 text-purple-300 border-t border-zinc-700"
}, "\uD83D\uDD0C Quét VST Directory\u2026"),
(!filteredInstruments.soundfonts.length && !filteredInstruments.vst.length) && /*#__PURE__*/React.createElement("p", { className: "text-xs text-zinc-500 py-4 text-center" }, "Kh\u00f4ng t\u00ecm th\u1EA5y nh\u1EA1c c\u1EE5 n\u00E0o")
))),
/* Plugin Manager Modal — scan VST3/AU (spec desktop 2026-08-08) */
vstScanOpen && /*#__PURE__*/React.createElement("div", {
className: "fixed inset-0 bg-black/80 backdrop-blur-sm z-[120] flex items-center justify-center p-4",
onMouseDown: e => e.stopPropagation(),
onClick: e => e.stopPropagation()
}, /*#__PURE__*/React.createElement("div", { className: "w-full max-w-2xl bg-[#1e1e24] border border-zinc-700 rounded-2xl p-5 shadow-2xl space-y-4 text-zinc-200" },
/*#__PURE__*/React.createElement("div", { className: "flex items-center justify-between border-b border-zinc-700 pb-3" },
/*#__PURE__*/React.createElement("h2", { className: "text-sm font-bold text-purple-400 flex items-center gap-2" }, "\uD83D\uDD0C Plugin Manager (VST3 / AU)"),
/*#__PURE__*/React.createElement("button", { onClick: () => setVstScanOpen(false), className: "text-zinc-400 hover:text-white text-lg" }, "\u2715")
),
/*#__PURE__*/React.createElement("div", { className: "space-y-2 max-h-[50vh] overflow-y-auto" },
vstPlugins.length === 0 && !vstScanning && /*#__PURE__*/React.createElement("p", { className: "text-xs text-zinc-500 text-center py-6" }, "Ch\u01B0a qu\u00E9t — nh\u1EADp \u0111\u01B0\u1EDDng d\u1EABn th\u01B0 m\u1EE5c ch\u1EE9a plugin (m\u1EB7c \u0111\u1ECBnh /opt/daw_engine/vst3) r\u1ED3i b\u1EA5m Scan."),
vstPlugins.map((plg) => /*#__PURE__*/React.createElement("div", {
key: plg.id,
onClick: () => {
setTrackInstrumentWithUndo(instrumentDropdownTrackId, plg.id, plg.name + " (" + plg.format + ")", undefined, undefined, { plugin_name: plg.name, format: plg.format, plugin_path: plg.path });
setVstScanOpen(false);
setVstPlugins([]);
},
className: "bg-[#22222a] hover:bg-[#2c2c36] border border-zinc-700/60 p-3 rounded-xl flex items-center justify-between cursor-pointer transition-all"
}, /*#__PURE__*/React.createElement("div", { className: "flex items-center gap-3" },
/*#__PURE__*/React.createElement("div", { className: "w-8 h-8 rounded-lg bg-purple-950/80 border border-purple-800 flex items-center justify-center text-purple-400 text-xs" }, "\uD83C\uDFB5"),
/*#__PURE__*/React.createElement("div", null,
/*#__PURE__*/React.createElement("div", { className: "text-xs font-bold text-white" }, plg.name),
/*#__PURE__*/React.createElement("div", { className: "text-[10px] text-zinc-400 font-mono" }, plg.path)
)
), /*#__PURE__*/React.createElement("span", { className: "text-[10px] font-mono font-bold bg-purple-950 text-purple-300 border border-purple-800 px-2 py-0.5 rounded-full" }, plg.format)))
),
/*#__PURE__*/React.createElement("div", { className: "pt-3 border-t border-zinc-700/80 space-y-1" },
/*#__PURE__*/React.createElement("label", { className: "block text-[10px] font-bold text-zinc-400 uppercase" }, "ADD VST DIRECTORY"),
/*#__PURE__*/React.createElement("div", { className: "flex gap-2" },
/*#__PURE__*/React.createElement("input", {
type: "text", value: vstScanPath,
onChange: e => setVstScanPath(e.target.value),
className: "flex-1 bg-[#141418] border border-zinc-700 rounded-lg px-3 py-1.5 text-xs text-zinc-200 font-mono outline-none focus:border-purple-500"
}),
/*#__PURE__*/React.createElement("button", {
onClick: async () => {
setVstScanning(true);
setVstScanError(null);
try {
const resp = await fetch('/api/v1/desktop/plugins/scan', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ custom_directories: [vstScanPath], scan_formats: ['VST3', 'AU'], force_rescan: true })
});
const data = await resp.json();
if (data.status === 'success') setVstPlugins(data.plugins || []);
else setVstScanError(data.detail || 'Scan thất bại');
} catch (err) {
setVstScanError('Lỗi kết nối: ' + err.message);
} finally {
setVstScanning(false);
}
},
disabled: vstScanning,
className: "px-5 py-1.5 bg-purple-600 hover:bg-purple-500 disabled:bg-zinc-700 text-white rounded-lg text-xs font-bold transition-all flex items-center gap-2"
}, vstScanning ? "Scanning..." : "Scan")
),
vstScanError && /*#__PURE__*/React.createElement("p", { className: "text-[10px] text-red-400" }, vstScanError),
/*#__PURE__*/React.createElement("p", { className: "text-[10px] text-zinc-600" }, "Windows: C:\\Program Files\\Common Files\\VST3 \u00B7 macOS: /Library/Audio/Plug-Ins/Components \u00B7 Linux: /opt/daw_engine/vst3, ~/.vst3")
)
))
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(/*#__PURE__*/React.createElement(App, null));
File diff suppressed because one or more lines are too long