V45.46: GUI embed VST full-panel trong DAW - phuc hoi embed (frame-capture ~10fps, relay input), bo toolbar header 'X Dong GUI' trong VstGuiEmbed + bo bar FX RT telemetry trong Mastering (phan tach GUI vs chain FX slot = border chain strip); dong GUI = chain card / module builtin / chon VST khac / onDead; projects API /disk list+open + api.js wrappers; plugins.py them SF_FXGUI_FLOAT=1 khi spawn bridge GUI; FxGuiServer/RenderFxJob fix GUI embed frame capture + show/hide re-anchor theo panel rect. Rebuild daw_vst_bridge+fx_vst_bridge+plugin_host v=202609032200.
This commit is contained in:
@@ -742,7 +742,8 @@ async def open_fx_gui(req: FxGuiRequest, current_user: dict = Depends(get_curren
|
||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT, text=True,
|
||||
close_fds=os.name != "nt",
|
||||
env=dict(os.environ, SF_PARENT_PID=str(os.getpid())),
|
||||
env=dict(os.environ, SF_PARENT_PID=str(os.getpid()),
|
||||
SF_FXGUI_FLOAT="1"),
|
||||
creationflags=_gui_creationflags)
|
||||
# Drain stdout NGAY TU DAU (daemon thread) và log TẤT CẢ các dòng
|
||||
# bridge in — gồm cả các dòng in TRƯỚC SF_FXGUI_PORT= ("[FxGui]
|
||||
|
||||
@@ -295,6 +295,54 @@ async def save_project_to_disk(req: SaveProjectRequest, authorization: Optional[
|
||||
}
|
||||
|
||||
|
||||
@router.get("/disk")
|
||||
async def list_disk_projects(authorization: Optional[str] = Header(None)):
|
||||
"""Danh sách file Ctrl-S desktop (Documents/SonicForgeDAW/Projects),
|
||||
mới nhất trước. Auth optional."""
|
||||
try:
|
||||
if authorization and authorization.startswith("Bearer "):
|
||||
decode_token(authorization.split(" ")[1])
|
||||
except Exception:
|
||||
pass
|
||||
out_dir = _os_projects_dir()
|
||||
items = []
|
||||
try:
|
||||
names = os.listdir(out_dir)
|
||||
except Exception:
|
||||
names = []
|
||||
for fn in names:
|
||||
if not fn.endswith(".sonicforge.json"):
|
||||
continue
|
||||
pth = os.path.join(out_dir, fn)
|
||||
try:
|
||||
mtime = os.path.getmtime(pth)
|
||||
size = os.path.getsize(pth)
|
||||
except Exception:
|
||||
continue
|
||||
items.append({"filename": fn, "name": fn[: -len(".sonicforge.json")], "mtime": mtime, "size_bytes": size})
|
||||
items.sort(key=lambda x: x["mtime"], reverse=True)
|
||||
return items
|
||||
|
||||
|
||||
@router.get("/disk/{filename}")
|
||||
async def get_disk_project(filename: str, authorization: Optional[str] = Header(None)):
|
||||
"""Đọc nội dung 1 file dự án trên đĩa (mở lại sau khi restart)."""
|
||||
try:
|
||||
if authorization and authorization.startswith("Bearer "):
|
||||
decode_token(authorization.split(" ")[1])
|
||||
except Exception:
|
||||
pass
|
||||
base = os.path.basename(filename)
|
||||
if not base.endswith(".sonicforge.json"):
|
||||
raise HTTPException(status_code=400, detail="Invalid project file")
|
||||
pth = os.path.join(_os_projects_dir(), base)
|
||||
if not os.path.isfile(pth):
|
||||
raise HTTPException(status_code=404, detail="Project not found on disk")
|
||||
with open(pth, "r", encoding="utf-8") as f:
|
||||
data_json = f.read()
|
||||
return {"filename": base, "name": base[: -len(".sonicforge.json")], "data_json": data_json}
|
||||
|
||||
|
||||
@router.post("/cloud")
|
||||
async def save_cloud_project(req: SaveProjectRequest, current_user: dict = Depends(get_current_user)):
|
||||
validated_data_json = validate_project_data(req.data_json)
|
||||
|
||||
Reference in New Issue
Block a user