官网部署脚本:发布到 getopenstats.com,资源 URL 带内容指纹并校验线上文件

This commit is contained in:
gentpan committed 2026-09-13 05:49:25 +05:00
1 parent 1f95de17d2
commit 99e970fa8f
2 files changed
+69 -19

No files matched your search

+50
View File
@@ -0,0 +1,50 @@
#!/bin/bash
# 把 web/ 发布到 getopenstats.com(Caddy 静态站点,前面是 Cloudflare 橙云)。
#
# 静态资源在 Cloudflare 缓存一天,同一个 URL 换了内容,线上仍会拿到旧文件。
# 所以每个资源 URL 带 ?v=内容指纹:内容变了指纹就变,URL 跟着变。
# 最后按公网实际拿到的内容校验,而不是只看源站。
set -euo pipefail
cd "$(dirname "$0")/.."
HOST="${SITE_HOST:-debian@15.204.80.137}"
KEY="${SITE_KEY:-$HOME/.ssh/gentpan.pem}"
ROOT="${SITE_ROOT:-/var/www/getopenstats.com}"
DOMAIN="${SITE_DOMAIN:-getopenstats.com}"
SSH=(ssh -i "$KEY" -o BatchMode=yes)
# 官网里的更新日志由 CHANGELOG.md 生成,发布前先同步
python3 Scripts/sync_changelog.py
# 先洗掉 ?v= 再算指纹,否则指纹会把自己算进去,内容没变也每次换值
STAMP="$( { cat web/styles.css web/replica.css web/app.js web/replica.js | /usr/bin/sed -E 's/\?v=[A-Za-z0-9]+//g'
find web/assets -type f | sort | xargs cat; } | shasum -a 256 | cut -c1-8)"
echo "内容指纹 v=$STAMP"
/usr/bin/sed -i '' -E "s/\?v=[A-Za-z0-9]+/?v=$STAMP/g" web/index.html
# 目录归部署用户所有,Caddy 只需读取
"${SSH[@]}" "$HOST" "sudo mkdir -p $ROOT && sudo chown -R \$(id -un):\$(id -gn) $ROOT"
rsync -az --delete -e "${SSH[*]}" web/ "$HOST:$ROOT/"
"${SSH[@]}" "$HOST" "sudo chmod -R a+rX $ROOT"
echo "已同步到 $HOST:$ROOT"
# 校验公网:Cloudflare 上拿到的文件大小与本地一致,首页引用的是新指纹
fail=0
for f in styles.css replica.css app.js replica.js; do
want=$(stat -f%z "web/$f")
got=$(curl -s -o /dev/null -w '%{size_download}' --max-time 20 "https://$DOMAIN/$f?v=$STAMP" || true)
if [ "$want" = "$got" ]; then
printf " ✅ %-12s %s B\n" "$f" "$got"
else
printf " ❌ %-12s 线上 %s B ≠ 本地 %s B\n" "$f" "$got" "$want"
fail=1
fi
done
refs=$(curl -s --max-time 20 "https://$DOMAIN/" | grep -c "?v=$STAMP" || true)
if [ "${refs:-0}" -gt 0 ]; then
printf " ✅ 首页 引用 %s 处新指纹\n" "$refs"
else
printf " ❌ 首页仍在引用旧指纹,或域名尚未解析\n"
fail=1
fi
exit $fail
+19 -19
View File
@@ -15,9 +15,9 @@
<meta property="og:site_name" content="OpenStats">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://getopenstats.com/assets/window-light.png">
<link rel="icon" href="assets/favicon.ico" sizes="48x48">
<link rel="icon" type="image/png" sizes="32x32" href="assets/favicon-32.png">
<link rel="apple-touch-icon" sizes="180x180" href="assets/apple-touch-icon.png">
<link rel="icon" href="assets/favicon.ico?v=b67d2007" sizes="48x48">
<link rel="icon" type="image/png" sizes="32x32" href="assets/favicon-32.png?v=b67d2007">
<link rel="apple-touch-icon" sizes="180x180" href="assets/apple-touch-icon.png?v=b67d2007">
<script>
// 在样式生效前确定主题,避免深色模式下先闪一下白底
try {
@@ -25,8 +25,8 @@
document.documentElement.dataset.theme = saved || (matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
} catch { document.documentElement.dataset.theme = "light"; }
</script>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="replica.css">
<link rel="stylesheet" href="styles.css?v=b67d2007">
<link rel="stylesheet" href="replica.css?v=b67d2007">
</head>
<body>
@@ -108,7 +108,7 @@
</span>
<span class="island__expanded" aria-hidden="true">
<span class="island__row">
<span class="island__brand"><img src="assets/icon.png" alt="" width="18" height="18">OpenStats</span>
<span class="island__brand"><img src="assets/icon.png?v=b67d2007" alt="" width="18" height="18">OpenStats</span>
<span class="island__health" data-bind="island-health">各项指标正常</span>
</span>
<span class="island__grid">
@@ -128,7 +128,7 @@
<!-- 左侧桌面图标 -->
<nav class="desk-icons" aria-label="快捷入口">
<a class="desk-icon" href="#download">
<span class="desk-icon__art desk-icon__art--dmg" aria-hidden="true"><img src="assets/icon.png" alt="" width="40" height="40"></span>
<span class="desk-icon__art desk-icon__art--dmg" aria-hidden="true"><img src="assets/icon.png?v=b67d2007" alt="" width="40" height="40"></span>
<span class="desk-icon__name">OpenStats.dmg</span>
</a>
<a class="desk-icon" href="https://github.com/gentpan/OpenStats#readme">
@@ -152,7 +152,7 @@
<span class="window__title">欢迎使用 OpenStats</span>
</div>
<div class="window__body hero__body">
<img class="hero__icon" src="assets/icon.png" alt="OpenStats 图标" width="72" height="72">
<img class="hero__icon" src="assets/icon.png?v=b67d2007" alt="OpenStats 图标" width="72" height="72">
<h1 class="hero__title" id="heroTitle">Mac 的状态,抬眼就看见</h1>
<p class="hero__lead">CPU、GPU、内存、网络与温度常驻菜单栏,还能调风扇、防休眠、一键清理。所有数据在本机读取,没有账号与统计上报。</p>
<div class="hero__actions">
@@ -172,7 +172,7 @@
<!-- 程序坞 -->
<nav class="dock" aria-label="程序坞">
<a class="dock__item" href="#features" title="访达"><span class="dock__art dock__art--finder" aria-hidden="true"></span></a>
<button class="dock__item" id="dockOpenStats" type="button" title="打开 OpenStats"><img class="dock__art" src="assets/icon.png" alt="OpenStats"></button>
<button class="dock__item" id="dockOpenStats" type="button" title="打开 OpenStats"><img class="dock__art" src="assets/icon.png?v=b67d2007" alt="OpenStats"></button>
<a class="dock__item" href="#thermal" title="风扇与防休眠"><span class="dock__art dock__art--fan" aria-hidden="true"></span></a>
<a class="dock__item" href="#cleanup" title="清理"><span class="dock__art dock__art--clean" aria-hidden="true"></span></a>
<a class="dock__item" href="https://github.com/gentpan/OpenStats" title="GitHub"><span class="dock__art dock__art--terminal" aria-hidden="true"></span></a>
@@ -249,8 +249,8 @@
<p class="note">公网 IP 查询与连接探测都可以在设置里关闭。修改 DNS 需要管理员权限。</p>
</div>
<figure class="shot shot--popover split__media">
<img class="shot--light" src="assets/popover-network-light.png" alt="OpenStats 网络详情弹窗" loading="lazy">
<img class="shot--dark" src="assets/popover-network-dark.png" alt="OpenStats 网络详情弹窗,深色" loading="lazy">
<img class="shot--light" src="assets/popover-network-light.png?v=b67d2007" alt="OpenStats 网络详情弹窗" loading="lazy">
<img class="shot--dark" src="assets/popover-network-dark.png?v=b67d2007" alt="OpenStats 网络详情弹窗,深色" loading="lazy">
</figure>
</div>
</section>
@@ -262,8 +262,8 @@
<p>主窗口、设置和弹窗共用同一底色,侧边栏与标题栏不分栏着色;窗口宽高都能拖动调整。</p>
</div>
<div class="shots">
<figure class="shot"><img src="assets/window-light.png" alt="OpenStats 主窗口仪表盘,浅色" loading="lazy"><figcaption>浅色</figcaption></figure>
<figure class="shot"><img src="assets/window-dark.png" alt="OpenStats 主窗口仪表盘,深色" loading="lazy"><figcaption>深色</figcaption></figure>
<figure class="shot"><img src="assets/window-light.png?v=b67d2007" alt="OpenStats 主窗口仪表盘,浅色" loading="lazy"><figcaption>浅色</figcaption></figure>
<figure class="shot"><img src="assets/window-dark.png?v=b67d2007" alt="OpenStats 主窗口仪表盘,深色" loading="lazy"><figcaption>深色</figcaption></figure>
</div>
</div>
</section>
@@ -284,7 +284,7 @@
<p>合盖后继续运行适合下载、渲染和远程连接。使用电池且电量低于下限时会自动关闭,避免在包里过热。</p>
<p class="note">风扇与合盖运行需要安装一次辅助工具。它只提供固定的几个操作,不执行任意命令,应用退出时自动恢复设置。</p>
</div>
<figure class="shot split__media"><img src="assets/thermal.png" alt="OpenStats 散热页面" loading="lazy"></figure>
<figure class="shot split__media"><img src="assets/thermal.png?v=b67d2007" alt="OpenStats 散热页面" loading="lazy"></figure>
</div>
</section>
@@ -301,7 +301,7 @@
</ul>
<p>只处理白名单目录;正在运行的应用会跳过,浏览器需先退出;删除前每一项再校验一次,所有操作写入日志。</p>
</div>
<figure class="shot split__media"><img src="assets/cleaner.png" alt="OpenStats 清理页面" loading="lazy"></figure>
<figure class="shot split__media"><img src="assets/cleaner.png?v=b67d2007" alt="OpenStats 清理页面" loading="lazy"></figure>
</div>
</section>
@@ -325,7 +325,7 @@
<section class="band band--alt" id="download">
<div class="shell narrow download">
<img src="assets/icon.png" alt="" width="96" height="96">
<img src="assets/icon.png?v=b67d2007" alt="" width="96" height="96">
<h2>下载 OpenStats</h2>
<p>使用 Developer ID 签名并经过 Apple 公证,打开时不会遇到安全拦截。</p>
<div class="hero__actions">
@@ -399,13 +399,13 @@
<footer class="footer">
<div class="shell footer__inner">
<span class="footer__brand"><img src="assets/icon.png" alt="" width="20" height="20">OpenStats</span>
<span class="footer__brand"><img src="assets/icon.png?v=b67d2007" alt="" width="20" height="20">OpenStats</span>
<span class="footer__fine">© 2026 GiantAccel, LLC · <a href="https://github.com/gentpan/OpenStats/blob/main/LICENSE">MIT 许可证</a> · <a href="https://github.com/gentpan/OpenStats">GitHub</a></span>
<span class="footer__fine">OpenStats 是独立的第三方应用,与 Apple 没有隶属关系。</span>
</div>
</footer>
<script src="app.js" defer></script>
<script src="replica.js" defer></script>
<script src="app.js?v=b67d2007" defer></script>
<script src="replica.js?v=b67d2007" defer></script>
</body>
</html>