Ver código fonte

Add asset folder opener and preserve selected library

bang 2 semanas atrás
pai
commit
4607af2ae9
2 arquivos alterados com 43 adições e 1 exclusões
  1. 27 0
      server.py
  2. 16 1
      web/index.html

+ 27 - 0
server.py

@@ -13,6 +13,7 @@
   GET  /assets/<game>/<path>  资源文件
   POST /api/generate          运行生成管线
   POST /api/export            把某 game 打包成 Cocos 整合包
+  POST /api/open-folder       打开某 game 的本地素材目录
   POST /api/delete            删除某 game 的资源库
 """
 
@@ -21,6 +22,8 @@ import mimetypes
 import os
 import posixpath
 import shutil
+import subprocess
+import sys
 import threading
 import time
 import traceback
@@ -397,6 +400,8 @@ class Handler(BaseHTTPRequestHandler):
         route = urlparse(self.path).path
         if route == "/api/export":
             return self._post_export()
+        if route == "/api/open-folder":
+            return self._post_open_folder()
         if route == "/api/delete":
             return self._post_delete()
         if route == "/api/slot-workflow":
@@ -481,6 +486,28 @@ class Handler(BaseHTTPRequestHandler):
         return self._send(200, {"ok": True, "logs": logs, "game": game,
                                 "pack": os.path.abspath(pack)})
 
+    def _post_open_folder(self):
+        try:
+            data = self._read_json_body()
+        except Exception as e:
+            return self._send(400, {"ok": False, "error": f"请求体不是合法 JSON: {e}"})
+        game = (data.get("game") or "").strip()
+        if not game or game not in list_games():
+            return self._send(400, {"ok": False, "error": f"无效的 game: {game!r}"})
+        target = os.path.abspath(os.path.join(OUT_ROOT, game))
+        if not target.startswith(os.path.abspath(OUT_ROOT) + os.sep) or not os.path.isdir(target):
+            return self._send(400, {"ok": False, "error": "素材目录不存在或路径非法"})
+        try:
+            if sys.platform == "darwin":
+                subprocess.Popen(["open", target])
+            elif os.name == "nt":
+                os.startfile(target)  # type: ignore[attr-defined]
+            else:
+                subprocess.Popen(["xdg-open", target])
+        except Exception as e:
+            return self._send(500, {"ok": False, "error": f"打开素材目录失败: {e}"})
+        return self._send(200, {"ok": True, "game": game, "path": target})
+
     def _post_delete(self):
         try:
             data = self._read_json_body()

+ 16 - 1
web/index.html

@@ -202,6 +202,7 @@
     <span class="meta">资源库(game):</span>
     <select id="gameSel"></select>
     <button class="ghost" id="reloadBtn">↻ 刷新</button>
+    <button class="ghost" id="openFolderBtn">📂 打开素材目录</button>
     <button id="exportBtn">📦 导出 Cocos 整合包</button>
     <button class="ghost" id="deleteBtn">🗑 删除该资源库</button>
     <span class="count" id="opMsg"></span>
@@ -426,7 +427,7 @@ $('#gameSel').onchange=e=>loadLibrary(e.target.value);
 function currentManifestGame(){
   try{ return JSON.parse($('#manifest').value||'{}').game || ''; }catch(e){ return ''; }
 }
-$('#reloadBtn').onclick=()=>loadLibrary(currentManifestGame() || $('#gameSel').value);
+$('#reloadBtn').onclick=()=>loadLibrary($('#gameSel').value || currentManifestGame());
 
 function opMsg(t,ok=true){ const m=$('#opMsg'); m.textContent=t; m.style.color=ok?'#7ee8ff':'#ff9d9d'; }
 function workflowMsg(t,ok=true){ const m=$('#workflowMsg'); m.textContent=t; m.style.color=ok?'#a99ccb':'#ff9d9d'; }
@@ -608,6 +609,20 @@ $('#exportBtn').onclick=async()=>{
   btn.disabled=false;
 };
 
+$('#openFolderBtn').onclick=async()=>{
+  const game=$('#gameSel').value;
+  if(!game||game==='(暂无)'){ opMsg('没有可打开的资源库',false); return; }
+  const btn=$('#openFolderBtn'); btn.disabled=true; opMsg('正在打开素材目录…');
+  try{
+    const r=await fetch('/api/open-folder',{method:'POST',headers:{'Content-Type':'application/json'},
+      body:JSON.stringify({game})});
+    const d=await r.json();
+    if(d.ok) opMsg('✅ 已打开 '+d.path);
+    else opMsg('❌ '+(d.error||'打开失败'),false);
+  }catch(e){ opMsg('请求失败: '+e,false); }
+  btn.disabled=false;
+};
+
 $('#deleteBtn').onclick=async()=>{
   const game=$('#gameSel').value;
   if(!game||game==='(暂无)'){ opMsg('没有可删除的资源库',false); return; }