feat: publish-from-local with builtin/market filter, file picker modal

This commit is contained in:
2026-07-27 10:11:00 +08:00
parent e94d862560
commit 2960d132ef
2 changed files with 73 additions and 1 deletions
+72
View File
@@ -763,3 +763,75 @@ async def api_market_delete(data: dict):
return {"ok": resp.status_code < 400}
except Exception as e:
return {"ok": False, "error": str(e)}
@router.post("/market/publish-local")
async def api_market_publish_local(data: dict):
import io, zipfile, json as _json
token = data.get("token", "")
dash_id = data.get("id", "")
pub_type = data.get("type", "dashboard")
if not token:
return {"error": "需要登录"}
try:
from models.dashboard import dashboard_manager
from models.scene import scene_manager
if pub_type == "scene":
scene = scene_manager.get(dash_id)
if not scene:
return {"error": "场景不存在"}
if scene.get("is_builtin"):
return {"error": "不能发布内置场景"}
buf = io.BytesIO()
with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as zf:
zf.writestr("scene.json", _json.dumps(scene, indent=2, ensure_ascii=False))
zip_data = buf.getvalue()
cfg = get_config()
url = cfg.get("market_url", "https://turbosu.yeij.top")
import httpx
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",""),
"dashb_pending": "true", "manifest_id": scene.get("id","")},
files={"file": (f"{dash_id}.tss", zip_data, "application/zip")},
)
return resp.json()
else:
theme_dir = dashboard_manager.get_dir(dash_id)
if not theme_dir:
return {"error": "仪表盘不存在"}
theme = dashboard_manager.get(dash_id)
if not theme or theme.get("is_builtin"):
return {"error": "不能发布内置或市场仪表盘"}
buf = io.BytesIO()
with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as zf:
for f in sorted(theme_dir.rglob('*')):
if f.is_file():
zf.write(f, f.relative_to(theme_dir))
zip_data = buf.getvalue()
cfg = get_config()
url = cfg.get("market_url", "https://turbosu.yeij.top")
import httpx
async with httpx.AsyncClient(timeout=30) as client:
resp = await client.post(
f"{url}/api/collections/dashboards/records",
headers={"Authorization": f"Bearer {token}"},
data={"name": theme.get("name",""), "category": theme.get("category",""),
"author": theme.get("author",""), "version": theme.get("version","1.0"),
"dashb_pending": "true", "manifest_id": theme.get("id",""),
"icon": theme.get("icon",""), "supported_games": theme.get("supported_games","all")},
files={"file": (f"{dash_id}.tsd", zip_data, "application/zip")},
)
return resp.json()
except Exception as e:
return {"error": str(e)}
+1 -1
View File
@@ -326,7 +326,7 @@ const PageMarket = {
<p style="color:var(--text-secondary);font-size:14px;margin-top:4px">浏览并安装社区分享的仪表盘和场景 <span id="m-status" style="color:var(--text-tertiary)"> 未登录</span></p>
</div>
<div style="display:flex;gap:8px">
<button id="btn-m-upload" class="btn btn-sm btn-secondary" style="display:none">发布仪表盘</button>
<button id="btn-m-upload" class="btn btn-sm btn-secondary" style="display:none">发布你的作品</button>
<button id="btn-m-login" class="btn btn-sm btn-primary">登录</button>
</div>
</div>