dsh-folia 4.10.0 → 4.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -801,6 +801,13 @@ window.__ModuleLoader__.load({
801
801
  "下载地址不在白名单里": "The download host is not allow-listed",
802
802
  "站点被关闭了(DSH_FOLIA_SITE=off)": "The site is disabled (DSH_FOLIA_SITE=off)",
803
803
  "这个文件不是 zip": "This file is not a zip",
804
+
805
+ // ── 助手皮肤:皮肤中心缺失时的引导(4.10.1)──────────────────────────
806
+ "皮肤中心没装:它是**独立插件** @linxin666/dsh-client-ui-skin-center(不在 dsh-web-all 里,那个只是聚合包)。装它才能启用皮肤:": "The skin centre is not installed: it is its own plugin, @linxin666/dsh-client-ui-skin-center (dsh-web-all is only an aggregate). Install it to enable skins:",
807
+ "已复制安装命令": "Install command copied",
808
+ "复制失败,请手动选中上面的命令": "Copy failed — select the command above manually",
809
+ "复制命令": "Copy command",
810
+ "先装皮肤中心,否则皮肤装好也没法启用": "Install the skin centre first, or the skin cannot be enabled",
804
811
  };
805
812
 
806
813
  // ── 内联模块:src/i18n-copy-picker.js —— 英文词表域:壁纸选择器与快捷面板(picker-* · quick-panel · sidebar-right · theme-follow)(构建期注入;勿手改本段)──
@@ -18343,11 +18350,33 @@ window.__ModuleLoader__.load({
18343
18350
  }, weT("刷新")),
18344
18351
  ));
18345
18352
 
18346
- children.push(React.createElement("div", {
18347
- key: "hint",
18348
- className: "we-picker__hint",
18349
- style: { margin: "6px 0 4px", opacity: 0.8 },
18350
- }, weT("皮肤包安装到皮肤中心目录;装完到「设置 → 皮肤中心」里点选即可启用。皮肤中心与本插件读同一个目录,无需重启。")));
18353
+ // 皮肤中心在不在,决定这段提示说什么:
18354
+ // 在 → "装完去皮肤中心点它"(本页签只负责落盘)
18355
+ // 不在 → 明说它是个**独立插件**(不在 dsh-web-all 里),给一条可复制的安装命令
18356
+ // unknown(探测失败)→ 保守地按"在"讲,不吓唬用户
18357
+ const skinCenter = (state && state.skinCenter) || "unknown";
18358
+ if (skinCenter === "absent") {
18359
+ children.push(React.createElement("div", {
18360
+ key: "hint-absent",
18361
+ className: "we-picker__hint",
18362
+ style: { margin: "6px 0 4px", color: "#ffd08a", lineHeight: "1.6" },
18363
+ }, weT("皮肤中心没装:它是**独立插件** @linxin666/dsh-client-ui-skin-center(不在 dsh-web-all 里,那个只是聚合包)。装它才能启用皮肤:")));
18364
+ children.push(React.createElement("div", { key: "cmd", style: { display: "flex", gap: "8px", alignItems: "center", margin: "0 0 6px" } },
18365
+ React.createElement("code", {
18366
+ style: { fontSize: "11px", padding: "3px 8px", borderRadius: "6px", background: "rgba(255,255,255,0.08)" },
18367
+ }, "dsh plugin --profile web add @linxin666/dsh-client-ui-skin-center"),
18368
+ React.createElement("button", {
18369
+ className: "we-picker__btn", type: "button",
18370
+ onClick: () => { try { navigator.clipboard.writeText("dsh plugin --profile web add @linxin666/dsh-client-ui-skin-center"); setNote({ ok: true, text: weT("已复制安装命令") }); } catch { setNote({ ok: false, text: weT("复制失败,请手动选中上面的命令") }); } },
18371
+ }, weT("复制命令")),
18372
+ ));
18373
+ } else {
18374
+ children.push(React.createElement("div", {
18375
+ key: "hint",
18376
+ className: "we-picker__hint",
18377
+ style: { margin: "6px 0 4px", opacity: 0.8 },
18378
+ }, weT("皮肤包安装到皮肤中心目录;装完到「设置 → 皮肤中心」里点选即可启用。皮肤中心与本插件读同一个目录,无需重启。")));
18379
+ }
18351
18380
 
18352
18381
  // 提示行常驻占位(与开机动画/桌宠页签同一条纪律:不因 note 出现/消失让面板跳高度)
18353
18382
  children.push(React.createElement("div", {
@@ -18405,6 +18434,7 @@ window.__ModuleLoader__.load({
18405
18434
  : React.createElement("button", {
18406
18435
  className: "we-picker__btn", type: "button",
18407
18436
  disabled: Boolean(busy),
18437
+ title: skinCenter === "absent" ? weT("先装皮肤中心,否则皮肤装好也没法启用") : undefined,
18408
18438
  onClick: () => act("install", { id: s.id, url: s.url }, s.title),
18409
18439
  }, busyThis ? weT("安装中…") : weT("安装")),
18410
18440
  );
@@ -49,6 +49,30 @@ function siteBase() {
49
49
  return base.replace(/\/+$/, '');
50
50
  }
51
51
 
52
+ /**
53
+ * 皮肤中心是否在线。
54
+ *
55
+ * 为什么由宿主探而不是前端探:两个插件跑在同一个 webServer 上,用请求自带的 Host 就能问到自己 ——
56
+ * 前端也能问,但宿主这一侧拿到的结果与"装没装"一一对应,而且不受浏览器缓存/跨源策略影响。
57
+ * 判据用**它自己的 catalog 路由**:该路由不需要鉴权(实测 200),404 就是没装。
58
+ */
59
+ const skinCenterProbe = { at: 0, state: 'unknown' };
60
+ async function probeSkinCenter(hostHeader, force) {
61
+ const now = Date.now();
62
+ if (!force && skinCenterProbe.at && now - skinCenterProbe.at < 30000) return skinCenterProbe.state;
63
+ let state = 'unknown';
64
+ if (hostHeader) {
65
+ try {
66
+ const r = await fetch('http://' + hostHeader + '/api/skin-center/v2/catalog', { signal: AbortSignal.timeout(4000) });
67
+ state = r.status === 404 ? 'absent' : (r.ok ? 'present' : 'present');
68
+ // 401/403 也说明插件在(只是该路由被别的版本加了鉴权);只有 404 才代表没装。
69
+ } catch { state = 'unknown'; }
70
+ }
71
+ skinCenterProbe.at = now;
72
+ skinCenterProbe.state = state;
73
+ return state;
74
+ }
75
+
52
76
  /** 站点列表缓存(30 秒):面板打开与"刷新"共用,避免每次都打站点。 */
53
77
  const siteCache = { at: 0, items: [], error: null };
54
78
  const SITE_TTL_MS = 30000;
@@ -238,6 +262,7 @@ export function registerSkinsRoutes(webServer, c) {
238
262
  const force = /[?&]refresh=1/.test(req.url || '');
239
263
  const site = await fetchSiteSkins(force);
240
264
  const installed = listInstalled();
265
+ const skinCenter = await probeSkinCenter(req.headers && req.headers.host, force);
241
266
  // ⚠️ 站点 slug 与本机皮肤 id **不总是同一个字符串**:站点上 slug 是全站唯一的,
242
267
  // 撞名时上传工具会加 `skin-` 前缀(实测 blue-throated-bee-eater 同时是桌宠 id)。
243
268
  // 所以比对要归一:两边都去掉可选的 `skin-` 前缀再比,否则会显示成"未安装"。
@@ -248,6 +273,7 @@ export function registerSkinsRoutes(webServer, c) {
248
273
  }
249
274
  sendJson(res, 200, {
250
275
  ok: true,
276
+ skinCenter,
251
277
  siteBase: siteBase(),
252
278
  siteError: site.error,
253
279
  installed,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-folia",
3
- "version": "4.10.0",
3
+ "version": "4.10.1",
4
4
  "description": "Folia 壁纸引擎:把本机 Wallpaper Engine 壁纸搬进 DSH 界面(场景实时渲染 / 视频 / 网页),内置液态玻璃与 Folia 吉祥物,并可从自建站点拉取壁纸。单包形态(组件已合并)。",
5
5
  "type": "module",
6
6
  "engines": {