mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 17:10:43 +00:00
下载区
- 管理页加一张「下载最新版」卡片,就一个按钮
自动指向 /v1/downloads 里最新的被控端整包,不用每次改页面
- GET /v1/downloads 列出成品
- GET /download/<文件> 直接给文件
只允许白名单后缀(.apk/.zip/.txt/.exe/.idsig)
文件名严格校验,挡目录穿越(../ 和 ..%2F 都试过)
- 卡片下面附一个 Gitee 历史版本入口
大文件
- 原来 read_bytes() 一次性读进内存再 write。
19MB 在 460MB 的设备上勉强,更要命的是 Cloudflare
有 100 秒的源站响应上限,数据越晚开始流动越容易被掐。
- 改成 64KB 分块流式发送,边读边发
实测:19MB 公网下载 40 秒完成,字节数完全一致
版本
- 三端分开打包(原来是一个合并 zip)
ykxmz-agent-1.5.0.zip 被控端
ykxmz-server-1.5.0.zip 服务器端
ykxmz-watch-1.5.0.apk 控制端(直接给 APK)
104 lines
3.5 KiB
Python
104 lines
3.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
r"""下载区简化成"一个链接"(用户要求)。
|
|
|
|
用户:"没有,你就放一个下载连接就行了"
|
|
|
|
所以把原来那套(文件列表 + 大小 + 大文件提示 + Gitee 备用入口)
|
|
全部去掉,只留**一行一个链接**,点了就能下。
|
|
|
|
链接指向中转自己的下载区(/v1/downloads 里最新的那个文件),
|
|
这样不管叫什么都自动指向最新的,不用每次改页面。
|
|
|
|
同时保留流式发送(19MB 走隧道本来就慢,
|
|
一次性读进内存再发更容易被 Cloudflare 100 秒上限掐断)。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import ast
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
RELAY = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\relay" r"\relay.py")
|
|
|
|
NEW_CARD = ''' <div class=panel id=dlPanel>
|
|
<div class=label>下载最新版</div>
|
|
<div id=dlBody class=tip>正在读…</div>
|
|
</div>'''
|
|
|
|
NEW_JS = '''// ---------------- 下载(就一个链接)----------------
|
|
(async () => {
|
|
const body = document.getElementById('dlBody');
|
|
if (!body) return;
|
|
try {
|
|
const r = await fetch('/v1/downloads');
|
|
const j = await r.json();
|
|
const files = (j && j.files) || [];
|
|
if (!files.length) {
|
|
body.innerHTML = '<span style="color:#8b949e">服务器上还没有成品。</span>';
|
|
return;
|
|
}
|
|
// 按名字里的版本号挑最新的那个整包;没有就挑第一个
|
|
const pick = files.find(f => /agent/i.test(f.name))
|
|
|| files.find(f => /\\.zip$/i.test(f.name))
|
|
|| files[0];
|
|
const mb = (pick.size / 1024 / 1024).toFixed(2);
|
|
body.innerHTML =
|
|
'<a href="/download/' + encodeURIComponent(pick.name) + '" '
|
|
+ 'style="display:inline-block;padding:10px 20px;border-radius:6px;'
|
|
+ 'background:#238636;color:#fff;text-decoration:none;'
|
|
+ 'font-weight:600;font-size:15px">'
|
|
+ '⬇ 下载 ' + pick.name + '</a>'
|
|
+ '<div style="color:#6e7681;font-size:12px;margin-top:8px">'
|
|
+ mb + ' MB · 也可以去 '
|
|
+ '<a href="https://gitee.com/xmz7891/ykxmz/releases" target="_blank" '
|
|
+ 'rel="noopener" style="color:#79c0ff">Gitee 历史版本</a>'
|
|
+ '</div>';
|
|
} catch (e) {
|
|
body.innerHTML = '<span style="color:#f85149">读不到:' + e + '</span>';
|
|
}
|
|
})();
|
|
|
|
// ---------------- 自动刷新 ----------------'''
|
|
|
|
|
|
def main() -> int:
|
|
text = RELAY.read_text(encoding="utf-8")
|
|
if "下载最新版" in text:
|
|
print(" 已经是简化版")
|
|
return 0
|
|
|
|
# 1) 卡片:把原来那张(可能已经改过)整块换掉
|
|
card = re.search(
|
|
r' <div class=panel id=dlPanel>.*?\n </div>\n', text, re.S)
|
|
if card:
|
|
text = text[:card.start()] + NEW_CARD + "\n" + text[card.end():]
|
|
print(" 卡片简化成一个「下载最新版」")
|
|
else:
|
|
print(" [失败] 找不到下载卡片")
|
|
return 1
|
|
|
|
# 2) JS:把"下载区"那一整段换成新的(从注释到"自动刷新"之前)
|
|
js = re.search(
|
|
r'// ---------------- 下载.*?// ---------------- 自动刷新 ----------------',
|
|
text, re.S)
|
|
if js:
|
|
text = text[:js.start()] + NEW_JS + text[js.end():]
|
|
print(" JS 简化成一个链接")
|
|
else:
|
|
print(" [失败] 找不到下载 JS 段")
|
|
return 1
|
|
|
|
RELAY.write_text(text, encoding="utf-8", newline="\n")
|
|
try:
|
|
ast.parse(text)
|
|
print(" relay.py 语法 OK")
|
|
except SyntaxError as exc:
|
|
print(f" 语法错误: 行 {exc.lineno}: {exc.msg}")
|
|
return 1
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|