启动器:游戏更新拆分为当前/历史双子页,新增关于我们页
- 游戏更新页改为「当前更新 / 历史更新」两个标签页,历史页显示条数 - 更新日志合并仓库 Release 与本地 更新日志.txt,按日期去重、仓库优先;断网时仅用本地记录 - 主导航新增「关于我们」,内容与游戏内控制台关于页一致(四行文案 + 赞助/公众号二维码) - 新增 /qr/<name> 白名单路由读取启动器目录 qr\ 下图片,防止目录穿越 - 二维码支持点击放大(灯箱),图片缺失时显示占位而不是破图 - 打包 spec 补入 qr 三张图,静态响应统一 Cache-Control: no-store
This commit is contained in:
1 parent
1dd3775510
commit
6a4b7e58d3
8 files changed
+311
-36
No files matched your search
+124
-4
@@ -16,6 +16,7 @@ import ctypes
|
||||
import json
|
||||
import os
|
||||
import queue
|
||||
import re
|
||||
import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
@@ -145,6 +146,16 @@ SPONSOR_IMG = os.path.join(BASE_DIR, "sponsor.png")
|
||||
if not os.path.exists(SPONSOR_IMG):
|
||||
SPONSOR_IMG = os.path.join(RES_DIR, "sponsor.png")
|
||||
|
||||
# 关于我们页的三张二维码:优先 EXE 同目录 qr\(可自行替换),其次打包内资源
|
||||
QR_FILES = {
|
||||
"alipay.png": "image/png",
|
||||
"wechat.png": "image/png",
|
||||
"gzh.jpg": "image/jpeg",
|
||||
}
|
||||
|
||||
# 断网时更新日志的兜底来源(EXE 同目录 / 服务端根目录的 更新日志.txt)
|
||||
LOCAL_CHANGELOG_NAME = "更新日志.txt"
|
||||
|
||||
# 数据库与实例配置候选路径(基于运行目录解析出的 SERVER_ROOT)
|
||||
def _instance_candidates():
|
||||
out = []
|
||||
@@ -373,6 +384,93 @@ def _release_summary(rel):
|
||||
}
|
||||
|
||||
|
||||
def _local_changelog():
|
||||
"""断网时的兜底:解析本地 更新日志.txt,按日期切成若干条(最新在前)。
|
||||
|
||||
文件长这样(日期行之间是正文):
|
||||
2026.11.05 更新:
|
||||
1.xxx
|
||||
2.xxx
|
||||
"""
|
||||
path = ""
|
||||
for d in (BASE_DIR, SERVER_ROOT):
|
||||
if not d:
|
||||
continue
|
||||
p = os.path.join(d, LOCAL_CHANGELOG_NAME)
|
||||
if os.path.exists(p):
|
||||
path = p
|
||||
break
|
||||
if not path:
|
||||
return []
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8", errors="ignore") as f:
|
||||
lines = f.read().splitlines()
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
items = []
|
||||
cur = None
|
||||
for ln in lines:
|
||||
s = ln.strip()
|
||||
m = re.match(r"^(\d{4})[.\-/](\d{1,2})[.\-/](\d{1,2})", s)
|
||||
if m:
|
||||
if cur:
|
||||
items.append(cur)
|
||||
date = "%s.%s.%s" % (m.group(1), m.group(2).zfill(2), m.group(3).zfill(2))
|
||||
cur = {
|
||||
"tag": date,
|
||||
"name": date + " 更新",
|
||||
"body": "",
|
||||
"published_at": "",
|
||||
"prerelease": False,
|
||||
"html_url": UPDATE_REPO_WEB,
|
||||
"assets": [],
|
||||
}
|
||||
continue
|
||||
if cur is not None and s:
|
||||
cur["body"] = (cur["body"] + "\n" + s).strip()
|
||||
if cur:
|
||||
items.append(cur)
|
||||
items.reverse() # 文件里是旧→新,接口要新→旧
|
||||
return items
|
||||
|
||||
|
||||
def _changelog_date_key(rel):
|
||||
"""从 tag / name / 发布时间里抽 20261105 这样的排序键;取不到返回空串。"""
|
||||
s = " ".join([rel.get("tag") or "", rel.get("name") or "", rel.get("published_at") or ""])
|
||||
m = re.search(r"(\d{4})[.\-/](\d{1,2})[.\-/](\d{1,2})", s)
|
||||
if not m:
|
||||
return ""
|
||||
return "%s%02d%02d" % (m.group(1), int(m.group(2)), int(m.group(3)))
|
||||
|
||||
|
||||
def _merge_changelog(remote, local):
|
||||
"""仓库发布记录 + 本地更新日志合并:按日期去重(仓库优先,内容更全),新的在前。
|
||||
|
||||
仓库没跟上发版时,本地 更新日志.txt 里的新条目会自动出现在「当前更新」。
|
||||
"""
|
||||
out, seen = [], set()
|
||||
for rel in remote or []:
|
||||
k = _changelog_date_key(rel)
|
||||
if k:
|
||||
if k in seen:
|
||||
continue
|
||||
seen.add(k)
|
||||
out.append(rel)
|
||||
for rel in local or []:
|
||||
k = _changelog_date_key(rel)
|
||||
if k:
|
||||
if k in seen:
|
||||
continue
|
||||
seen.add(k)
|
||||
out.append(rel)
|
||||
|
||||
dated = [r for r in out if _changelog_date_key(r)]
|
||||
undated = [r for r in out if not _changelog_date_key(r)]
|
||||
dated.sort(key=_changelog_date_key, reverse=True)
|
||||
return dated + undated
|
||||
|
||||
|
||||
def flow_start_game(account_username=None):
|
||||
"""一键开始游戏;account_username 为空时使用默认账号。"""
|
||||
log("== 开始游戏 ==")
|
||||
@@ -590,6 +688,8 @@ class Handler(BaseHTTPRequestHandler):
|
||||
self._send_file(SPONSOR_IMG, "image/png")
|
||||
else:
|
||||
self._json({"error": "赞助二维码尚未提供"}, 404)
|
||||
elif path.startswith("/qr/"):
|
||||
self._send_qr(path[len("/qr/"):])
|
||||
# 启动器接口
|
||||
elif path == "/api/status":
|
||||
self._api_status()
|
||||
@@ -792,19 +892,39 @@ class Handler(BaseHTTPRequestHandler):
|
||||
})
|
||||
|
||||
def _api_update_changelog(self, qs):
|
||||
"""获取所有发布的更新日志。"""
|
||||
"""获取所有发布的更新日志;连不上仓库时退回本地 更新日志.txt。"""
|
||||
force = qs.get("force", ["0"])[0] == "1"
|
||||
releases, err = _fetch_releases(force=force)
|
||||
if err:
|
||||
self._json({"ok": False, "error": err, "releases": []})
|
||||
remote = [] if err else [_release_summary(r) for r in (releases or [])]
|
||||
local = _local_changelog()
|
||||
merged = _merge_changelog(remote, local)
|
||||
if not merged:
|
||||
self._json({"ok": False, "error": err or "没有任何更新记录", "releases": []})
|
||||
return
|
||||
self._json({
|
||||
"ok": True,
|
||||
"current": CURRENT_VERSION,
|
||||
"releases": [_release_summary(r) for r in (releases or [])],
|
||||
"releases": merged,
|
||||
# local = 完全没连上仓库;merged = 仓库记录 + 本地补齐
|
||||
"source": "remote" if remote else "local",
|
||||
"local_count": len(local),
|
||||
"warning": err,
|
||||
"web_url": UPDATE_REPO_WEB,
|
||||
})
|
||||
|
||||
def _send_qr(self, name):
|
||||
"""关于我们页的二维码图片:EXE 同目录 qr\\ 优先,其次打包内资源。"""
|
||||
ctype = QR_FILES.get(name)
|
||||
if not ctype:
|
||||
self._json({"error": "not found"}, 404)
|
||||
return
|
||||
for d in (os.path.join(BASE_DIR, "qr"), os.path.join(RES_DIR, "qr")):
|
||||
p = os.path.join(d, name)
|
||||
if os.path.exists(p):
|
||||
self._send_file(p, ctype)
|
||||
return
|
||||
self._json({"error": "二维码未配置"}, 404)
|
||||
|
||||
def _api_logs(self):
|
||||
logs = []
|
||||
while True:
|
||||
|
||||
Reference in new issue
Block a user