feat: market scenes tab - upload/install with dependency check
This commit is contained in:
+87
-1
@@ -557,8 +557,13 @@ async def api_market_upload(file: UploadFile = File(...), name: str = "", catego
|
||||
return {"error": "无效的仪表盘文件:缺少 manifest.json"}
|
||||
if 'index.html' not in names:
|
||||
return {"error": "无效的仪表盘文件:缺少 index.html"}
|
||||
|
||||
manifest = _json.loads(zf.read('manifest.json').decode('utf-8'))
|
||||
|
||||
if not manifest.get('id'):
|
||||
return {"error": "manifest.json 缺少 id"}
|
||||
if not manifest.get('name'):
|
||||
return {"error": "manifest.json 缺少 name"}
|
||||
|
||||
actual_name = name or manifest.get('name', file.filename.replace('.tsd', ''))
|
||||
actual_category = category or manifest.get('category', 'community')
|
||||
actual_author = author or manifest.get('author', 'Unknown')
|
||||
@@ -604,3 +609,84 @@ async def api_market_install(id: str = "", filename: str = ""):
|
||||
return {"ok": ok}
|
||||
except Exception as e:
|
||||
return {"ok": False, "error": str(e)}
|
||||
|
||||
|
||||
# ---- Market Scenes ----
|
||||
@router.get("/market/scenes")
|
||||
async def api_market_scenes():
|
||||
import httpx
|
||||
cfg = get_config()
|
||||
url = cfg.get("market_url", "http://127.0.0.1:5301")
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=10) as client:
|
||||
resp = await client.get(f"{url}/api/collections/scenes/records?sort=-created&perPage=50")
|
||||
return resp.json()
|
||||
except Exception:
|
||||
return {"items": []}
|
||||
|
||||
|
||||
@router.post("/market/scenes/upload")
|
||||
async def api_market_upload_scene(file: UploadFile = File(...), token: str = ""):
|
||||
import io, zipfile, json as _json
|
||||
if not file.filename or not file.filename.endswith('.tss'):
|
||||
return {"error": "仅支持 .tss 文件"}
|
||||
try:
|
||||
zip_data = await file.read()
|
||||
with zipfile.ZipFile(io.BytesIO(zip_data), 'r') as zf:
|
||||
if 'scene.json' not in zf.namelist():
|
||||
return {"error": "缺少 scene.json"}
|
||||
scene = _json.loads(zf.read('scene.json').decode('utf-8'))
|
||||
if not scene.get('name'):
|
||||
return {"error": "scene.json 缺少 name"}
|
||||
deps = set()
|
||||
for canvas in scene.get('canvases', []):
|
||||
for p in canvas.get('placements', []):
|
||||
if p.get('dashboard_id'):
|
||||
deps.add(p['dashboard_id'])
|
||||
except zipfile.BadZipFile:
|
||||
return {"error": "无效的 zip 文件"}
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
import httpx as _httpx
|
||||
cfg = get_config()
|
||||
url = cfg.get("market_url", "http://127.0.0.1:5301")
|
||||
try:
|
||||
async with _httpx.AsyncClient(timeout=30) as client:
|
||||
resp = await client.post(
|
||||
f"{url}/api/collections/scenes/records",
|
||||
headers={"Authorization": f"Bearer {token}"},
|
||||
data={"name": scene.get('name'), "description": scene.get('description',''), "game_id": scene.get('game_id',''), "author": scene.get('author','') or "Unknown", "dashb_pending": True},
|
||||
files={"file": (file.filename, zip_data, file.content_type)},
|
||||
)
|
||||
result = resp.json()
|
||||
result["dependencies"] = list(deps)
|
||||
return result
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
@router.get("/market/scenes/install")
|
||||
async def api_market_install_scene(id: str = "", filename: str = ""):
|
||||
import httpx, io, zipfile, json as _json
|
||||
cfg = get_config()
|
||||
url = cfg.get("market_url", "http://127.0.0.1:5301")
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=60, follow_redirects=True) as client:
|
||||
resp = await client.get(f"{url}/api/files/scenes/{id}/{filename}")
|
||||
zip_data = resp.content
|
||||
missing = []
|
||||
with zipfile.ZipFile(io.BytesIO(zip_data), 'r') as zf:
|
||||
if 'scene.json' in zf.namelist():
|
||||
scene = _json.loads(zf.read('scene.json').decode('utf-8'))
|
||||
from models.dashboard import dashboard_manager
|
||||
for canvas in scene.get('canvases', []):
|
||||
for p in canvas.get('placements', []):
|
||||
did = p.get('dashboard_id', '')
|
||||
if did and not dashboard_manager.get(did):
|
||||
missing.append(did)
|
||||
from models.scene import scene_manager
|
||||
ok = scene_manager.import_scene_zip(zip_data)
|
||||
return {"ok": ok, "missing_dashboards": missing}
|
||||
except Exception as e:
|
||||
return {"ok": False, "error": str(e)}
|
||||
|
||||
Reference in New Issue
Block a user