From e9097e5893ce7259c6295bd4f60c94ae6f5f1f98 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Sat, 3 Oct 2026 08:37:54 +0800 Subject: [PATCH] =?UTF-8?q?feat(icon):=20=E7=BA=B8=E9=A3=9E=E6=9C=BA?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=EF=BC=88=E7=AB=99=E7=82=B9=20favicon=20+=20?= =?UTF-8?q?=E6=89=A9=E5=B1=95=E5=90=84=E5=B0=BA=E5=AF=B8=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 站点首页此前显示的是 Dashy 上游的 logo —— index.html 里那几条 优先级高于我们的门户图标, 而扩展的 PNG 是占位图(128px 只有 9 种颜色、alpha 通道还是乱的)。 - portal/favicon.svg:纸飞机(圆角渐变底 + 白色折纸机头朝右上 + 两道尾迹), 几何收在 8..56 安全区,避免贴边被圆角裁切 - 由该 SVG 派生 favicon.ico(16/32/48)、apple-touch-icon(180)、 web-icons/favicon-{16,32,64}、扩展 icon{16,48,96,128} - patch-index.py:删掉上游 icon link 并显式指向 /favicon.svg(幂等, 重复执行 unchanged);上游 web-icons 那批也覆盖一份作双保险 - Dockerfile 与 zd-host.sh 都 COPY 这些图标进镜像 - 验证:nginx 沙箱实测 /favicon.svg、/web-icons/*、/apple-touch-icon.png 均 200; 16px 下人眼仍可辨识为纸飞机 - .amo-upload-uuid(web-ext 生成的 UUID)改为忽略 --- .gitignore | 6 ++ Dockerfile | 6 ++ deploy/sign-firefox.sh | 115 ++++++++++++++++++++++++++++ deploy/zd-host.sh | 5 ++ extension/chrome/icons/icon128.png | Bin 307 -> 5194 bytes extension/chrome/icons/icon16.png | Bin 79 -> 552 bytes extension/chrome/icons/icon48.png | Bin 124 -> 1736 bytes extension/firefox/.amo-upload-uuid | 1 - extension/firefox/icons/icon128.png | Bin 307 -> 5194 bytes extension/firefox/icons/icon16.png | Bin 79 -> 552 bytes extension/firefox/icons/icon48.png | Bin 124 -> 1736 bytes extension/firefox/icons/icon96.png | Bin 223 -> 3813 bytes portal/apple-touch-icon.png | Bin 0 -> 7789 bytes portal/favicon.ico | Bin 1113 -> 556 bytes portal/favicon.svg | 26 ++++++- portal/web-icons/favicon-16x16.png | Bin 0 -> 552 bytes portal/web-icons/favicon-32x32.png | Bin 0 -> 1138 bytes portal/web-icons/favicon-64x64.png | Bin 0 -> 2403 bytes web/patch-index.py | 19 ++++- 19 files changed, 175 insertions(+), 3 deletions(-) create mode 100755 deploy/sign-firefox.sh delete mode 100644 extension/firefox/.amo-upload-uuid create mode 100644 portal/apple-touch-icon.png create mode 100644 portal/web-icons/favicon-16x16.png create mode 100644 portal/web-icons/favicon-32x32.png create mode 100644 portal/web-icons/favicon-64x64.png diff --git a/.gitignore b/.gitignore index 695f0a4..1ab0ece 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,10 @@ __pycache__/ *.pyc # 本机 agent 工具的会话产物,不入库 +# web-ext sign 生成的工具产物(UUID 上传标识),不入库 +.amo-upload-uuid +**/.amo-upload-uuid + +# pi 任务日志/产物,不入库 +.pi/ .pi-glla/ diff --git a/Dockerfile b/Dockerfile index 4b62c02..d51c044 100644 --- a/Dockerfile +++ b/Dockerfile @@ -84,6 +84,12 @@ COPY searxng-settings.yml /etc/searxng/settings.yml COPY conf.example.yml /app/defaults/conf.yml COPY admin/index.html /app/admin/index.html COPY portal /app/portal +# 站点图标:纸飞机。覆盖 Dashy 自带的 web-icons/favicon-*.png, +# 这样即使将来上游 index.html 变了、patch 失效,标签栏仍是我们的图标。 +COPY portal/favicon.svg /app/dashy/favicon.svg +COPY portal/favicon.ico /app/dashy/favicon.ico +COPY portal/apple-touch-icon.png /app/dashy/apple-touch-icon.png +COPY portal/web-icons/ /app/dashy/web-icons/ # 浏览器扩展安装页与安装包(通过 /extension/ 访问) COPY web/extension/install.html /app/dashy/extension/install.html diff --git a/deploy/sign-firefox.sh b/deploy/sign-firefox.sh new file mode 100755 index 0000000..3a4599c --- /dev/null +++ b/deploy/sign-firefox.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash +# Firefox 扩展:构建 → lint → AMO unlisted 签名 → 发布到数据卷 +# +# 为什么需要这个脚本(实测踩坑,2026-10-03): +# 1. 正式版 Firefox 要求扩展经 AMO 签名,未签名一律拒绝并报成「插件损坏」。 +# 2. 签名包一旦生成就与内容绑定 —— 改一行代码就必须重新签名, +# 所以「签名」必须跟着「改代码」这一步自动发生,不能靠人记得手动做。 +# 3. 签名是 AMO 生成的产物,不该进版本库(签名与源码脱节 + 是二进制), +# 因此落在数据卷里,跨部署存活;nginx 优先供给它(见 nginx.conf)。 +# +# 凭据:只从环境变量读,绝不写进本仓库(AGENTS.md §6 脱敏铁律) +# WEB_EXT_API_KEY / WEB_EXT_API_SECRET —— AMO 开发者页面「API 密钥」里的 +# JWT issuer:secret。属于程序化签名凭据,与账号密码无关。 +# 先在 https://addons.mozilla.org/developers/ → 你的扩展 → 设置 → API 密钥 获取。 +# +# 用法: +# WEB_EXT_API_KEY=... WEB_EXT_API_SECRET=... deploy/sign-firefox.sh # 签名并发布 +# deploy/sign-firefox.sh --check # 只跑 lint,不签名 +set -euo pipefail + +SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +EXT_DIR="$SRC/extension/firefox" +WEB_EXT="${WEB_EXT:-npx --yes web-ext@8}" + +CHECK_ONLY=0 +[ "${1:-}" = "--check" ] && CHECK_ONLY=1 + +echo "== 1/4 语法与规范检查 ==" +node --check "$EXT_DIR/background.js" +node --check "$EXT_DIR/options.js" +node --check "$EXT_DIR/detect.js" +# lint 必须 0 error:AMO 用的是同一个 addons-linter,error 会被直接拒收。 +# 注意 notice 不阻塞上传,但要能看见(提示 FUTURE/MV3 之类,不静默吞掉)。 +LINT_OUT="$(mktemp)" +trap 'rm -f "$LINT_OUT"' EXIT +(cd "$EXT_DIR/.." && $WEB_EXT lint --source-dir=firefox --output text) >"$LINT_OUT" 2>&1 || { + cat "$LINT_OUT"; echo "!! lint 执行失败" >&2; exit 1; } +grep -E '^(errors|warnings|notices)' "$LINT_OUT" | sed 's/^/ /' +grep -qE '^errors +0' "$LINT_OUT" || { cat "$LINT_OUT"; echo "!! 有 error,AMO 会拒收" >&2; exit 1; } +grep -E '^(NOTICES|WARNINGS):' -A6 "$LINT_OUT" | grep -vE '^--$' | sed 's/^/ /' || true + +VER="$(python3 -c "import json;print(json.load(open('$EXT_DIR/manifest.json'))['version'])")" +echo " 版本: $VER" + +if [ "$CHECK_ONLY" = "1" ]; then + echo "--check 模式:跳过签名与发布。" + exit 0 +fi + +echo "== 2/4 AMO 签名(unlisted 自分发)==" +[ -n "${WEB_EXT_API_KEY:-}" ] && [ -n "${WEB_EXT_API_SECRET:-}" ] || { + cat >&2 <<'EOF' +!! 缺少 AMO 凭据。请设置环境变量后重试: + WEB_EXT_API_KEY='user::' \ + WEB_EXT_API_SECRET='' \ + deploy/sign-firefox.sh + 凭据在 https://addons.mozilla.org/developers/ → 你的扩展 → 设置 → API 密钥 获取。 + 不要把凭据写进仓库或任何会被提交的文件(AGENTS.md §6)。 +EOF + exit 2; } + +ART="$(mktemp -d)" +trap 'rm -rf "$ART" "$LINT_OUT"' EXIT +(cd "$EXT_DIR/.." && $WEB_EXT sign --source-dir=firefox \ + --artifacts-dir="$ART" --channel=unlisted --no-input) 2>&1 \ + | grep -vE 'DeprecationWarning|trace-deprecation|no version information' | sed 's/^/ /' + +XPI="$(ls "$ART"/*.xpi 2>/dev/null | head -1 || true)" +[ -n "$XPI" ] || { echo "!! 未产出签名包" >&2; exit 1; } + +echo "== 3/4 校验签名包 ==" +# 不能只看「web-ext 说成功」:签名条目缺失的包装上去照样报「插件损坏」。 +python3 - "$XPI" <<'PY' +import json, sys, zipfile +z = zipfile.ZipFile(sys.argv[1]) +names = z.namelist() +need = ['META-INF/mozilla.rsa', 'META-INF/mozilla.sf', 'META-INF/cose.manifest'] +missing = [n for n in need if n not in names] +if missing: + sys.exit(f'!! 签名条目缺失: {missing}') +m = json.loads(z.read('manifest.json')) +g = m['browser_specific_settings']['gecko'] +print(f" 签名条目齐备 版本={m['version']} id={g['id']}") +print(f" data_collection={g.get('data_collection_permissions')}") +PY + +echo "== 4/4 发布到数据卷 ==" +# 没给 NAVI_HOST 就只把包落到本地,供人工上传。 +if [ -z "${NAVI_HOST:-}" ]; then + OUT="${1:-$SRC}/navi-firefox-signed.xpi" + cp "$XPI" "$OUT" + echo " 未设 NAVI_HOST,仅本地输出: $OUT" + echo " (线上发布:NAVI_HOST=user@host NAVI_SSH_PASS=... deploy/sign-firefox.sh)" + exit 0 +fi +SSH_PASS="${NAVI_SSH_PASS:-}" +if [ -n "$SSH_PASS" ]; then + SSH=(sshpass -p "$SSH_PASS" ssh -o StrictHostKeyChecking=no "$NAVI_HOST") + SCP=(sshpass -p "$SSH_PASS" scp -q -o StrictHostKeyChecking=no) +else + SSH=(ssh -o StrictHostKeyChecking=no "$NAVI_HOST") + SCP=(scp -q -o StrictHostKeyChecking=no) +fi +DATA_DIR="${NAVI_DATA_DIR:-/vol1/docker/navi-data}" +STAMP="$(date +%Y%m%d%H%M%S)" + +"${SCP[@]}" "$XPI" "$NAVI_HOST:$DATA_DIR/extension/.navi-firefox.xpi.new" +# 先备份再原子替换:中途失败不会让线上退化成半个文件 +"${SSH[@]}" "set -e + cd $DATA_DIR/extension + [ -f navi-firefox.xpi ] && cp -a navi-firefox.xpi navi-firefox.xpi.bak-\$(date +%s) + mv .navi-firefox.xpi.new navi-firefox.xpi + echo \" 已发布: \$(sha256sum navi-firefox.xpi | cut -d' ' -f1)\"" | sed 's/^/ /' + +echo "SIGN_OK version=$VER" diff --git a/deploy/zd-host.sh b/deploy/zd-host.sh index 45f2bf1..1823b6b 100644 --- a/deploy/zd-host.sh +++ b/deploy/zd-host.sh @@ -69,6 +69,11 @@ COPY searxng-settings.yml /etc/searxng/settings.yml COPY conf.example.yml /app/defaults/conf.yml COPY admin/index.html /app/admin/index.html COPY portal /app/portal +# 站点图标:纸飞机(覆盖 Dashy 自带的那套,双保险) +COPY portal/favicon.svg /app/dashy/favicon.svg +COPY portal/favicon.ico /app/dashy/favicon.ico +COPY portal/apple-touch-icon.png /app/dashy/apple-touch-icon.png +COPY portal/web-icons/ /app/dashy/web-icons/ COPY web/extension/install.html /app/dashy/extension/install.html COPY ext/navi-chrome.zip /app/dashy/extension/navi-chrome.zip COPY ext/navi-firefox.xpi /app/dashy/extension/navi-firefox.xpi diff --git a/extension/chrome/icons/icon128.png b/extension/chrome/icons/icon128.png index 76eaa6b95df47ea5cd1355e108c320324af0243d..f3813591e9b51e69cb4d90b6a48b6cdb9e443a4b 100644 GIT binary patch literal 5194 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 bP5uE(6VE-U$jRgI00000NkvXXu0mjf$I|^S delta 60 zcmZ3%;y*#sjERAPVZy`=Gax1A>EaktF(>&!^sh-OM+{aah8+HIm4QL$*BpWAf3HUY PRWNwE`njxgN@xNAU)~j( diff --git a/extension/chrome/icons/icon48.png b/extension/chrome/icons/icon48.png index f78ca3d89054cfc6139722fd4c5f7906a82c9f13..48f1551bd98fa028981c01a9a621d427cf83a87e 100644 GIT binary patch delta 1730 zcmV;z20i(F$PJJge+B>m09OL}hX4Qo24YJ`L;(K){{a7>y{D4^00wxrfR6fE!-eQ6$mbaget@x zS4iAYkVsK~A_b%n8mJl)foSA5ZC%HviR(I!?bz{8{KKwye`n6e#jfr3cy@QzOM~;? z?4I$=InO!se(#y}2s!kX*OQ-jtbf$NVL@6@>I5875P-~Q)V654--vBblu_WSv79Q8 zCI9fdZ&go)aZ2#OBY#co5uaZOJhf5S65+$ziwY;I=VHJ7_4g!|a{`Z^OMD&6NrCE3 z1i#WYaM5b)f60^2$;`S5WZ+MiVv|o2ex+Zb*VovAcGtQ#l&{m9VnrSAjCfpf_(VC~y?5&ZHw6DAdFGwSX#V{FH&h#epUDM>2 z5}p4m_$@9xyvyP7Jq}IV(&o68Q05cLLOgFDuKWLludfmgwmKYabGWCR70oUwiz(CvB4>dmNgo1JoHU`7jkv zUy$-(e|laEj^TdN@C{YMq1_IL9$0IWpgaqcaV66Q*KXQKV??fjVr}x-I>X^shlfIJ z5|mY#h%3IX9=q^wKhl_yYM>aKJaV7I*V-MLbJ!#(CB5<~yL!y?VSJ`=0Yiiuh-#C= z_d9gA=C?_hrV>iRUwiE1NgD~iU=0+q$-W(if9_U?FEtgmNtl-7GN^xiXd^FR&Kk&P zlSf+|o@k41lQ3n+Wwxw^;fZJkoU;bPPHe0ax_3Er?{=sv(k4M=$7N6>Q>*qV1P>uK z5O(4-dmWzrw2N$f!B-TF%b?!6YKu#}D7Ja!iqFsgnPPk)*RatP7MIylg==Hc3wTWp ze-t{gXVh|eJjuab4#zqjs$<37jSy zR7U4~?*Ej~UTfBI<%-LoZp|qvuQ>Rke`+AuZrv_))(fi2nSRTyd1Zf-;XC_X>bIur zBVSwwb@`)c=@X27w^(=sbkrI4?l7Rr+aqas0p1z0yniFffd?GExzAzVCudv+HE_Lf z`h@LSZZYtcWzf}VXxM77R_PhB+?dtXjumRFguYSB(3Ite-Q}cgx_Fa$3V3!we_4oY z(eROLzyVrogw8rcnIkNvlz$CdrWe=3w`>=_*kVZfaJJXyPnSK8J?H}I4J_e9+)Gc$ zX5E_Jq5SES?}<5Y4LAncwj1`;3R_$Ol;Ii6`(rj;a9Qw;)k0TGx`?lgrqkq&KA(<8 z!@g#NYoN+NRhghb!h^W4%*LTVe^2@pdfd;u4|FvcKG$g2;tIDGl?xwPdPdg6H*FIh zy3b%l=o?jrr_**&;Khp`bAdt@(*KF5i3xA?c+AY{hTsd(q4$`ihW9W zH=$O{Df7ptWM1K?cM86A+hp3pYcCv+y=MUS4#a*XaQ3c&hgsM1W61ms;ONU*Q{gS0 z$I`jU;e9Mm{OtLPvygdD4DiY`GVN>ZfG8I?G5l;c{F(^>oP17ZhMQxL8Tb*fxQXCZ zgjZdqD;plNEELptJbycPuPf!x8p}6SXcwhPw74HYCD}x|Daf#~_M8>->I=tX?}c&x Y7jP1%r|VPs>i_@%07*qoM6N<$f`Q{}Jpcdz delta 105 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 bP5uE(6VE-U$jRgI00000NkvXXu0mjf$I|^S delta 60 zcmZ3%;y*#sjERAPVZy`=Gax1A>EaktF(>&!^sh-OM+{aah8+HIm4QL$*BpWAf3HUY PRWNwE`njxgN@xNAU)~j( diff --git a/extension/firefox/icons/icon48.png b/extension/firefox/icons/icon48.png index f78ca3d89054cfc6139722fd4c5f7906a82c9f13..48f1551bd98fa028981c01a9a621d427cf83a87e 100644 GIT binary patch delta 1730 zcmV;z20i(F$PJJge+B>m09OL}hX4Qo24YJ`L;(K){{a7>y{D4^00wxrfR6fE!-eQ6$mbaget@x zS4iAYkVsK~A_b%n8mJl)foSA5ZC%HviR(I!?bz{8{KKwye`n6e#jfr3cy@QzOM~;? z?4I$=InO!se(#y}2s!kX*OQ-jtbf$NVL@6@>I5875P-~Q)V654--vBblu_WSv79Q8 zCI9fdZ&go)aZ2#OBY#co5uaZOJhf5S65+$ziwY;I=VHJ7_4g!|a{`Z^OMD&6NrCE3 z1i#WYaM5b)f60^2$;`S5WZ+MiVv|o2ex+Zb*VovAcGtQ#l&{m9VnrSAjCfpf_(VC~y?5&ZHw6DAdFGwSX#V{FH&h#epUDM>2 z5}p4m_$@9xyvyP7Jq}IV(&o68Q05cLLOgFDuKWLludfmgwmKYabGWCR70oUwiz(CvB4>dmNgo1JoHU`7jkv zUy$-(e|laEj^TdN@C{YMq1_IL9$0IWpgaqcaV66Q*KXQKV??fjVr}x-I>X^shlfIJ z5|mY#h%3IX9=q^wKhl_yYM>aKJaV7I*V-MLbJ!#(CB5<~yL!y?VSJ`=0Yiiuh-#C= z_d9gA=C?_hrV>iRUwiE1NgD~iU=0+q$-W(if9_U?FEtgmNtl-7GN^xiXd^FR&Kk&P zlSf+|o@k41lQ3n+Wwxw^;fZJkoU;bPPHe0ax_3Er?{=sv(k4M=$7N6>Q>*qV1P>uK z5O(4-dmWzrw2N$f!B-TF%b?!6YKu#}D7Ja!iqFsgnPPk)*RatP7MIylg==Hc3wTWp ze-t{gXVh|eJjuab4#zqjs$<37jSy zR7U4~?*Ej~UTfBI<%-LoZp|qvuQ>Rke`+AuZrv_))(fi2nSRTyd1Zf-;XC_X>bIur zBVSwwb@`)c=@X27w^(=sbkrI4?l7Rr+aqas0p1z0yniFffd?GExzAzVCudv+HE_Lf z`h@LSZZYtcWzf}VXxM77R_PhB+?dtXjumRFguYSB(3Ite-Q}cgx_Fa$3V3!we_4oY z(eROLzyVrogw8rcnIkNvlz$CdrWe=3w`>=_*kVZfaJJXyPnSK8J?H}I4J_e9+)Gc$ zX5E_Jq5SES?}<5Y4LAncwj1`;3R_$Ol;Ii6`(rj;a9Qw;)k0TGx`?lgrqkq&KA(<8 z!@g#NYoN+NRhghb!h^W4%*LTVe^2@pdfd;u4|FvcKG$g2;tIDGl?xwPdPdg6H*FIh zy3b%l=o?jrr_**&;Khp`bAdt@(*KF5i3xA?c+AY{hTsd(q4$`ihW9W zH=$O{Df7ptWM1K?cM86A+hp3pYcCv+y=MUS4#a*XaQ3c&hgsM1W61ms;ONU*Q{gS0 z$I`jU;e9Mm{OtLPvygdD4DiY`GVN>ZfG8I?G5l;c{F(^>oP17ZhMQxL8Tb*fxQXCZ zgjZdqD;plNEELptJbycPuPf!x8p}6SXcwhPw74HYCD}x|Daf#~_M8>->I=tX?}c&x Y7jP1%r|VPs>i_@%07*qoM6N<$f`Q{}Jpcdz delta 105 zcmX@XTQfm2nTdgc;YLE<1t8_@>EaktG3V_$M_vX69)^vY2lg`_dB`L#)2}9aA@X-k z>ZisD6D9=M3J3`atzvfqg0Bu99v&;?I5;^uuQDqtE$R~B__g+$-9iI6Bmn~k<6s^R zP(`iMlx|9?B9%&1ZQ4|#id5B7q89$B6tz+m6sZAB5T&Y0AP}H9hENlX1AZm0!S*g| zvoEjh-Sxg^X6K$?|F|>WJ9p2HsYce;c^0{)IO;OOg^)bOYS_YT|mt z{j#Eufea_ZUz13_Rhv9$)Z^e;JF>yh3euO{L1aA{H%!l z{?nZeKP8}y2Ds@RZH$b^ch}rbIQBr5)8)Vhu{0i-P;CufqfAMGA z6W6B?HISZOsEu$dwHJi%eRfpsW9h?_WYeotn^oi&HTZJ}KeatYvSFD4HrL?KIedUdB8e?Vk!wRMK&AGJ z2fk-ly~7B!*Wj0C7a$^V!z#lg8|%u0?|r^DBFIwE8vG*d3!}oVYYbaD92)C|1O0Bs zzQw{%rLBu7x}V%uE`%3PV$hTG)TW<}924TsiCwksAEj_U5Q?+Zw~2?GB5Y{Cj~aoSamW3a7>_ znxky~yz<#2#T4*jfxmWX1wN$jfX^WOw42$qx_md2O~G(8s6)Ns!IyL&;6Lco3_l|9 zr4@#+Tp5m=2`XE-8Pt1SZbsS8m9Gr=5au|bitwAG!tJXK_gv|)xG@|z6I8Bn)2~=U zIXzz9^h2(?hcgbS68yFnVawX^-Aquq!p)#Q?6;x97s40^gbcq<;7iL5_g2Zx1eGt` z4C?)^nVrIbU->v7MEDD%!sgXpG*c}%lTG=;O~0m-&^KJ#^g}UqFMk{m68yC-!kudz zZm+VN$)7~5QgiW>CFntT*>h`0!CMVO{z2>xK43=2Hp3 zlyEbs1IN8eR|CEPCM=(SV9@gI9SQ#R*GYy;?BuGcQo~KZ6gbkCeflA+0jTjOR+@n- zyw&6K$j=izb1=!&bm2-?Q>BKRK@E*66H_zChYcT1-vJ?ya1$=P@S)3Jzn1Z-wq_W zrPbl<>m3&6na~R>-1KWY3CD+WzjhQRe8K;QOsN@A9{kJZ3pcGY7$5wkRo?Bf#HPJ{ zRbf}R%bw#dceOj*|GC*6by(qMP)GVLuALkB5W+a16!@za3OBDdIA#XEwaV@u%kZSm zDs&tc9+=3Z@@QggV^8KCD92>AKjtWf?-*j#W`uL=8?mti6vf9gl4}tQB4S&S~;m#`^ zmZiS@GM%1CD!V?m44f?tf9ZT-ONYajc85z-=Xvs1Nn&wjNu#i0zObxGxTGHHD|{A_ zj(+9}zEH+Epcwd#b>8Z>4XYgLolN*=W6I8BE~mx|!*6L6HnbWRGzbf#!gb3H0!$^~ zNB^6|rpgd?ycHLhHwnw2_)y|Fpb-411MQa@)-4hoU+vRdCq^uL zdo4*fPoYxVO?9xL)es4uCuKi+((T1jQRTt^IBbvGklNMsW2JuH#$9m@;zEI>iAQ$}RdZFV|VP$jbiVw!* zs+<^A4i0!RelhSHBXG-FhfAWF4SBHFGI%!g

M>=O^%PX_?uaE}%2j$t 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 delta 1105 zcmV-X1g`t61lb4>000310RRvX00031AOJ%Ikq{YwKmY&$KnMl^0063Kaozv`00DDS zM?wIu&K&6g000DMK}|sb0I`n?{9y$E000SaNLh0L01m?d01m?e$8V@)000BnNklM zOeA8nC^cG#LK7KvkS55pR+he1_V30UO|Q!4ZN5-&h2x;Ta^}q~5pbpxrK2&qiN-v|rcSqxZaj z_=SX%cPEjr7-c_6`yVK-6Db zpJsEu`1ADGM}Gn#RdWyk;dQc1<^KT!yPkYU;(^$OF{>SnI6U@{Df|%+xL`m-|2ZVw zgm&*k?fu0C1KLO5BjLc7kvCSG4ax0#ZRRlh&0p^=f(?LG9WUIZHG7@K27YaS5WD;k z_2V6a4QM=Y5ea8Z=J97m_^}2s5Ntr*t`h}O<#T-{d|3l91Q^h;_l%wzdZl+g{)U7t z6<^i>42K3l{^rHl1!6)d(_rKN^GJ*xI>*20t;cTqC?0TNKx+6k5@iSf=6x{^3}_n| zMWT3&*Ioc;0mvA9pWfrZ0H9}o@;4H;6kxFgOJ=@5?{R1V&~f)e;on|)z4s*+Ymyq7 zvDW^<5Dy42002QCtkO#m5R6BjN00#~m5hK?7o1TqMz8@UAQnd4|JU8caLIu1APtZP zNCTt+(g10IGyqpr3(^2-fHXiFAPtZPNCR+1wIB`1MWR%@ge$5AW&)s={cVgy6+hb96C(ef3~4Y8f$%X})Z)VEM!3!`Ogf|}#?mMyS2GS1oY9fTC3 z54# Xt+q|4t \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + diff --git a/portal/web-icons/favicon-16x16.png b/portal/web-icons/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..d84f62cbb89f4fc9b7a5b512a20ca44483315acb GIT binary patch literal 552 zcmV+@0@wYCP);{(b{*?9D}*0k-7{spHUjP^Uu z9(43?7XVf(MzLa)%71O6PIzxh7~Ag{8+4>&)>olwl zrn}F}p}Ss9MISJnRrY0s*9(Egym9}TXGbh#VsHY_*TQf6sitDrHesn?%q<0u>{fb! z4@-f`8PCpMA(t~&^48r@E>Km2)t^Q-C7c*g@tn@m1@DQL|aqpf{XRlhAM=ojDr(E*ZYwJ#6abwvJzkr%A%7 q3%pXpZ()dPYBsH&b9b)yP5uE(&poKf$>Z<<0000+McRO>B58LTZ zcW3(}(E3d#yLaZy`P_T%IcM(*A#FJ|vD(FbPgGtJcwCffQ4j?~{&VIEjZMV8U_AZo zwy5-gem-6s|K#M$k`0&=eA)JGcCS%ABuY)OqkDuGKkrrK)i3tNduJvv4gXRUSz`FK zPr2own-9NHc~SCVkM%FZ%8Pw=H8;fDOn%Ro9gZj)FI~#KX+&lB{{Tl6F!GiWcx)-* zF@dKW4exG^mA+%ye_`weedDLmie@JzEq%z>N_ z!;{J{12)pHdq3bYfhQXbyILJuSDBf{<}2KsRMbM(Wn1bOaPI}4j0?}LGwe(`)K$&& zGyqiLMq2R{MkZ{&>lMKzh`?gusig2ii$i-;KFm=X$tbxzm){395kFv%~hr@?kF4q?ccPSe-+*EL;>!xs|Vo39WTz!SI|9H#1st|7^cs9v(~}YR|i` zTRuFU;$}0~S1v6K+i-j{oKJTB%aje@T>zBgAv{l)Gu26Fw^mqu^_*^L@R_h3^L}>0D5|aO|wdz_6vhQmAsl6jf;NmHFYb zClG?yCxoqyhG*9qM$<~ifKNJ`ci5N|+8PWo14n-L$YhlV6GFoZVRb^NsR+XF&kLWG z1A$T8z>a1^%m_dHZTaJ}#hcFLRK20C!O%ObTp3j|SvYjY!`i%$gbQ_X;m?acW8*qM zJjj8t(UcEg_xR+zf>FYSjcW}L*9sS|DuXu*$u)T0@=ce|?oEY;(K%=r1Q!K2$|!(W z$DpOokg69lQ}9#2W%O?856j8(9vjvQEo%(d#+2)0y5QrP5#@HVkt?vJ$*^<1LsL@t z>zd`eUOy5p3hKk*4v)zkbPoE9IUA0<#&RB^eRg8NWDb5EvfLO~utk|0;dpdHIr`%i zS4VWAa10E%pr46Kd)UbO(EU$o6DbD|#^)|ZzY_%)0M+AW_@T-pqI5?ZEdsu%BRL>& zJLXLtG#%T;a}9e8a%^rFJ6V(l(B<~aajtG5X^+e2@I(T4z?MT4<50^rN7Cp$gQvd(}07*qoM6N<$ Ef=*-{HUIzs literal 0 HcmV?d00001 diff --git a/portal/web-icons/favicon-64x64.png b/portal/web-icons/favicon-64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..feccdff2f04a22e96ed4cf0a2e1c049d54dcc9db GIT binary patch literal 2403 zcmV-p37qzcP)1jm<{AWBgwO%a$t2qh&{ zX+b3jsM-o4@dF8w3ffBaM^!GB+Wu)#D-~3=MKpw>UVx$|+{#r@2#FIerXjY$#EzZV zabi2(>zS`VcGq4X?|RqkH6->cS!X;xGkcyn-+b?!Icp)GRHgOV_yvx--vqf7SRt@d zlyU&kj=DK6X8> z-iy#uvJ0IX_^Ew^Yg8Y%*t>V!Sl&CM0l4^uNR#90c2QYZ(hL3U;4}LiM!9GEO@ZGc z>Dp-qp!KlB%X5sF54O2V2$h&#Xq0m)8`uDso+T9 z+nIx4(uMWA!VT8Q0JUrhmq&j^hLQuIDk|&{W$Ao{A1^C+eE-qtP3Zv;fc3kg zH-PS#@9-JzhvFvCwEbooGN=lwKU+ZXh*DGLMt%q&t-E4hHrU+@2tIur3xxv9jluoa z0)$6kQ8W_!h7pz41qh!kTYIem>gEf)-@v+6hTB{H`Qa55S?d#6ak|4-2Zi;GhAUef zLS@4K!){*qRQr0LC>5tGd_#?JMYBU|gM;6JmhD|LF zElbB2vbYLI!-`ti_o*!e9szu(3w(7T8Rl25aag=4eP&XsaAZtLC=85PC=gy0e5X2m z!(w4$qr;`CFwdreh!RUiJ#Tes!SDdSQxV>8;KDNvSD)?BQacgm*>o(bj3p+1f9Dgo zV0Zz1rxJWsP`JFou&H@!m}k>SEcuhx&`HI*g~Ow%2>86=o2rG4O%Cf<=MHnP!inVF z&(xle?Tp})N$_)m_Zzsd&aion!`XSl+^d)iM#|AYsv#Zo&?iSrGl>s3YXU#u5K?xLweYnDhs$RX=Go-6JFhVeOLHhq+hT?9QvVJKdt- z#XAL{aQK>lu%X_txv6wv?o}?k%Ty$$3=V5i@Q^VDpfLF6YT>E|hYe?yHq5=sWp`d3 z=(R<|i-MWyov$bpS{9o*g`dvuyn3fgi-s3cFGglE=lAzp?s_4{gKsAo$`hW&YC5~i zR6GHFgH!FVP^=k+_^Kx^PMhsmI0B^?!0R2va^B*Ftb_Srt6M}m4|mHxO-=eJ-r3QZWa|{ zcbRf6bRV^|g3p-*i+!H&8CHJzYMkHyH^GS+;z$7x*}%y zeU^A4`&6n92^TjSe5p8puSYqVTJUuATmH4*Wy|@KZ@bSxg@Fox(oG@>2)oL_N##IK zmaXq1;ipDG4*1G4VPjMB4wCBZ*qHKupJm|WL^ygsptfANX!S&XIM{FL8kqd%_L+SN z&RroiEz7={B0$IoA)oNOr{fF_YsugzCBa z`(Zn!Pix^1uOtZPc?LKu zAT&A8drl|^k0>J%&3>T;!l%nS+Y+p;6B?JBWcVM`xqwHY*C2d2qdA{C9v@To^|<`I z-DPjLEg5{;8Xx&j(i+=3vw!8S1n{WR>qF%qpw|}yKN3-1Jm9gz=`wQ>@agu0Bgzx6 z#pxNG`Z=Y52QbLXa{XVm!m-hQQ5H=HpKHlH7w|dzEFruosG2XCC$`Ec%7Y6H9%z4H zTUna{aGk)a_2&U7v=T)x0U^Kd;kEp-yHZ0%5UaBybR*- zz4ZSOPI?9{9}V1Pgs0{&JTXyw?R|FyJJQUP2H>IFBp&t!u0wff{=v(jvHJCUe-L^# zlUc|nRr&6t(c1;?7p3y_hv#)4`kkL{3w`WG%{~Ar-SXJUGi}`bLR4-L@0Te~5BPRb z`N@6T0)NlNIPCzWb?c*JE3Ip`3T#CAqChQ5@Dzg|6*#0yuZX;Yl_wwAR@Rn}?f>*F Vzh4zP-_-yB002ovPDHLkV1npjp6dVr literal 0 HcmV?d00001 diff --git a/web/patch-index.py b/web/patch-index.py index c049aed..08bf9b3 100644 --- a/web/patch-index.py +++ b/web/patch-index.py @@ -12,13 +12,24 @@ import sys CSS_TAG = '' JS_TAG = '' +# Dashy 自带的 logo(/web-icons/favicon-*.png)会被浏览器优先选中, +# 于是站点标签栏显示上游 logo 而不是我们的纸飞机。 +# 做法:删掉那些 ,再显式指向我们自己的 /favicon.svg。 +# 为什么用“删掉”而不是“改路径”:index.html 来自上游镜像,每次重建可能被重置, +# 删标签幂等,且不依赖上游将来还叫 web-icons。 +ICON_LINK_RE = re.compile(r'[ \t]*]*rel=["\']icon["\'][^>]*>\s*', re.I) +OUR_ICONS = ('\n' + '') + def patch(html: str) -> str: html = re.sub(r'[ \t]*\s*', '', html) html = re.sub(r'[ \t]*\s*', '', html) + html = re.sub(r'[ \t]*' + re.escape(OUR_ICONS) + r'\s*', '', html) + html = ICON_LINK_RE.sub('', html) if '' in html: - html = html.replace('', CSS_TAG + '', 1) + html = html.replace('', CSS_TAG + OUR_ICONS + '', 1) if '' in html: html = html.replace('', JS_TAG + '', 1) @@ -36,6 +47,12 @@ def main(path: str) -> int: if 'href="/navi.css"' not in patched or 'src="/navi.js"' not in patched: print('patch failed: tags missing after patch', file=sys.stderr) return 1 + if 'web-icons/favicon' in patched: + print('patch failed: upstream Dashy icon links survived', file=sys.stderr) + return 1 + if '/favicon.svg' not in patched: + print('patch failed: our icon link missing', file=sys.stderr) + return 1 with open(path, 'w', encoding='utf-8') as fh: fh.write(patched) print('patched %s (%s)' % (path, 'changed' if patched != original else 'unchanged'))