spark-server/deploy/popadmin/patch_api_doc.py
DESKTOP-L8OUL9F\gfl0034 5d05eb0804 chore(deploy): geo snippet、popadmin 补丁与订阅包名脚本
补充 world geo nginx snippet、OpenAPI/geo 热更新脚本,以及 popadmin package_name 定价补丁,便于运维对齐。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-30 09:17:18 +08:00

113 lines
4.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""Replace popadmin apiDoc() to embed sparkapi /docs; bump index cache bust."""
from __future__ import annotations
import re
import sys
from pathlib import Path
NEW_API_DOC = """async apiDoc() {
const DOC = 'https://sparkapi.wyrs365.com';
const bust = '202609241556';
const embedUrl = DOC + '/docs?from=popadmin&v=' + bust;
$('content').innerHTML = `
<div class="note" style="margin-bottom:12px">
Spark 客户端 HTTP API 权威文档(OpenAPI / Swagger)内嵌自
<a href="${DOC}/docs" target="_blank" rel="noopener">${DOC}/docs</a>
· 规范 <code>${DOC}/openapi.yaml</code>
· 含音乐分类、多广场 <code>square</code> / <code>squarenovel</code> / <code>squaresteps</code> / <code>squarehealth</code> 等
· <a href="${DOC}/docs" target="_blank" rel="noopener">新窗口打开</a>
· <a href="${DOC}/docs/enums" target="_blank" rel="noopener">枚举</a>
· <a href="${DOC}/docs/errors" target="_blank" rel="noopener">错误码</a>
</div>
<iframe id="sparkApiDocFrame" title="Spark API 文档" src="${embedUrl}"
style="width:100%;height:calc(100vh - 160px);min-height:640px;border:1px solid var(--border);border-radius:10px;background:#0b1220"
referrerpolicy="no-referrer-when-downgrade"></iframe>`;
},"""
CACHE_BUST = "202609241556-apidoc"
def normalize_newlines(text: str) -> str:
return text.replace("\r\n", "\n").replace("\r", "\n")
def double_crlf_style(body: str) -> str:
"""Match production/local popadmin.js style: blank line between every line, CRLF."""
lines = [ln.rstrip() for ln in body.strip("\n").split("\n")]
return "\r\n\r\n".join(lines) + "\r\n\r\n"
def patch_js(path: Path) -> bool:
raw = path.read_bytes()
text = normalize_newlines(raw.decode("utf-8"))
# Match from async apiDoc() through the closing `},` before next top-level sibling
# (pages object ends with apiDoc then `};`)
pat = re.compile(
r"async apiDoc\(\)\s*\{.*?\n \},",
re.DOTALL,
)
m = pat.search(text)
if not m:
print(f"FAIL: apiDoc() not found in {path}", file=sys.stderr)
return False
new_block = NEW_API_DOC.strip()
# Detect if original uses blank-line-between-lines style
sample = m.group(0)[:80]
uses_double = "\n\n " in m.group(0) or m.group(0).count("\n\n") > 5
if uses_double:
# Keep double-newline + we write back as CRLF later if original was CRLF
dbl = "\n\n".join(ln.rstrip() for ln in new_block.split("\n"))
replacement = dbl
else:
replacement = new_block
text2 = text[: m.start()] + replacement + text[m.end() :]
if raw.count(b"\r\n") > raw.count(b"\n") // 2:
out = text2.replace("\n", "\r\n").encode("utf-8")
else:
out = text2.encode("utf-8")
path.write_bytes(out)
print(f"OK js: {path} ({len(out)} bytes)")
return True
def patch_index(path: Path) -> bool:
raw = path.read_text(encoding="utf-8")
new, n = re.subn(
r'(src="/popadmin/js/popadmin\.js)\?v=[^"]+"',
rf'\1?v={CACHE_BUST}"',
raw,
count=1,
)
if n == 0:
print(f"FAIL: popadmin.js script tag not found in {path}", file=sys.stderr)
return False
path.write_text(new, encoding="utf-8", newline="\n")
print(f"OK index: {path} bust={CACHE_BUST}")
return True
def main() -> int:
root = Path(__file__).resolve().parent
targets = sys.argv[1:]
if not targets:
ok = patch_js(root / "popadmin.js")
idx = root / "popadmin.index.html"
if idx.exists():
ok = patch_index(idx) and ok
return 0 if ok else 1
ok = True
for t in targets:
p = Path(t)
if p.name.endswith(".js") or "popadmin.js" in p.name:
ok = patch_js(p) and ok
elif "index" in p.name or p.suffix == ".html":
ok = patch_index(p) and ok
else:
print(f"skip unknown {p}", file=sys.stderr)
return 0 if ok else 1
if __name__ == "__main__":
raise SystemExit(main())