dsh-folia 4.15.0 → 4.15.2
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 +39 -2
- package/lib/routes/skins.js +49 -7
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -18570,8 +18570,15 @@ window.__ModuleLoader__.load({
|
|
|
18570
18570
|
|
|
18571
18571
|
const installed = (state && state.installed) || [];
|
|
18572
18572
|
const activeId = (state && state.active) || "";
|
|
18573
|
+
// 「皮肤中心记着哪套」≠「屏上现在是哪套」:壁纸在台上时皮肤会 withhold 自己,
|
|
18574
|
+
// 但它持久化的 active 不会自动清(我们 4.15.1 起在用户选壁纸时主动清一次)。
|
|
18575
|
+
// 这台机器的旧状态(或清理失败)仍可能出现"壁纸在播、页签却标使用中",所以这里先看
|
|
18576
|
+
// 我们的壁纸标记,标了就不把 active 说成"使用中",而是说"已让位"。
|
|
18577
|
+
const wallpaperOn = (() => {
|
|
18578
|
+
try { return Boolean(document && document.body && document.body.hasAttribute("data-we-wallpaper")); } catch { return false; }
|
|
18579
|
+
})();
|
|
18573
18580
|
/** 这个 id 是不是"正在用"的那套(两边都归一后比,站点 slug 可能带 skin- 前缀)。 */
|
|
18574
|
-
const isActiveSkin = (id) => Boolean(activeId) && normSkinId(activeId) === normSkinId(id);
|
|
18581
|
+
const isActiveSkin = (id) => Boolean(activeId) && !wallpaperOn && normSkinId(activeId) === normSkinId(id);
|
|
18575
18582
|
|
|
18576
18583
|
/**
|
|
18577
18584
|
* 站点条目 → 本机已装皮肤的真实 id(皮肤中心只认这个)。
|
|
@@ -18592,7 +18599,19 @@ window.__ModuleLoader__.load({
|
|
|
18592
18599
|
if (state) {
|
|
18593
18600
|
children.push(React.createElement("div", { key: "installed-head", className: "we-picker__hint" },
|
|
18594
18601
|
weT("本机已装({n})", { n: installed.length }),
|
|
18595
|
-
|
|
18602
|
+
// 壁纸在台上时不说"使用中":皮肤已让位,说了就是骗人(实测:壁纸在播却标皮肤使用中)
|
|
18603
|
+
activeId
|
|
18604
|
+
? (wallpaperOn
|
|
18605
|
+
? weT(" · 皮肤已让位(壁纸在使用中):{name}", { name: activeId })
|
|
18606
|
+
: weT(" · 使用中:{name}", { name: activeId }))
|
|
18607
|
+
: ""));
|
|
18608
|
+
if (activeId && wallpaperOn) {
|
|
18609
|
+
children.push(React.createElement("div", {
|
|
18610
|
+
key: "yield-note",
|
|
18611
|
+
className: "we-picker__hint",
|
|
18612
|
+
style: { margin: "0 0 6px", opacity: 0.8 },
|
|
18613
|
+
}, weT("当前是壁纸在台上,皮肤中心记着的这套没有在画。点「应用」会让皮肤上台(壁纸自动让位)。")));
|
|
18614
|
+
}
|
|
18596
18615
|
// 「恢复默认」:清空选择、回到官方外观。只有确实有皮肤在用的时候才有意义。
|
|
18597
18616
|
if (activeId) {
|
|
18598
18617
|
children.push(React.createElement("button", {
|
|
@@ -18634,6 +18653,17 @@ window.__ModuleLoader__.load({
|
|
|
18634
18653
|
[s.version ? "v" + s.version : "", skinFmtBytes(s.bytes), s.hasHooks ? weT("含动效钩子") : "",
|
|
18635
18654
|
notListed ? weT("皮肤中心未收录") : ""]
|
|
18636
18655
|
.filter(Boolean).join(" · ")),
|
|
18656
|
+
// 未收录时把**原因直接印在卡片上**(不只放在 title 里):实测用户看不到悬浮提示,
|
|
18657
|
+
// 只能看到一句"未收录",于是只能来问"为什么"。
|
|
18658
|
+
notListed
|
|
18659
|
+
? React.createElement("div", {
|
|
18660
|
+
style: { fontSize: "11px", lineHeight: "1.5", color: "#ffd08a", opacity: 0.95, margin: "2px 0 4px" },
|
|
18661
|
+
}, weT("原因:{why}", {
|
|
18662
|
+
why: (Array.isArray(s.catalogWarnings) && s.catalogWarnings.length)
|
|
18663
|
+
? s.catalogWarnings.slice(0, 2).join(";")
|
|
18664
|
+
: weT("皮肤中心没有给出原因(常见于它还没重扫,或它的用户皮肤目录与我们的不同)"),
|
|
18665
|
+
}))
|
|
18666
|
+
: null,
|
|
18637
18667
|
React.createElement("div", { style: { display: "flex", gap: "6px", alignItems: "center" } },
|
|
18638
18668
|
// 「应用」= 写皮肤中心的 active + 广播 `dsh-skin-applied`,就地切换(不刷新页面)。
|
|
18639
18669
|
isActive
|
|
@@ -21095,6 +21125,13 @@ window.__ModuleLoader__.load({
|
|
|
21095
21125
|
&& typeof skinYieldActive === "function" && skinYieldActive()) {
|
|
21096
21126
|
exitSkinYield("manual-pick", { skipRestore: true });
|
|
21097
21127
|
}
|
|
21128
|
+
// 「最后动作优先」的另一半:**用户选了壁纸** ⇒ 皮肤中心那边的 selection 也该清掉。
|
|
21129
|
+
// 否则它的 active 一直留着上一套皮肤,页签读了它就显示「使用中」——可屏上其实是壁纸
|
|
21130
|
+
//(它自己检测到 `body[data-we-wallpaper]` 就 withhold 了)。实测症状:壁纸在播、页签却标着
|
|
21131
|
+
// "皮肤使用中"。fire-and-forget:写失败不影响这次壁纸应用(页签按读到的事实显示)。
|
|
21132
|
+
if (id && opts && opts.fromManual) {
|
|
21133
|
+
try { apiPostJson("/skins/activate", { id: "" }, { parse: "always" }).catch(() => {}); } catch { /* ignore */ }
|
|
21134
|
+
}
|
|
21098
21135
|
reportClientDiag("apply", "id=" + String(id || "").slice(0, 40));
|
|
21099
21136
|
// 手动切换/清除/revalidate:取消进行中的轮换准备(staged/探测元素全部
|
|
21100
21137
|
// 释放),并丢弃任何滞留的就绪元素。轮换提交(fromRotation)例外 ——
|
package/lib/routes/skins.js
CHANGED
|
@@ -39,8 +39,44 @@ const SKIP_EXEC_RE = /\.(exe|dll|bat|cmd|com|scr|ps1|sh|msi|vbs|wsf|hta|lnk|jar)
|
|
|
39
39
|
function dshHome() {
|
|
40
40
|
return process.env.DSH_HOME || join(process.env.APPDATA || homedir(), 'dsh-desktop', 'harness');
|
|
41
41
|
}
|
|
42
|
-
/**
|
|
43
|
-
function skinsRoot() { return join(
|
|
42
|
+
/** 皮肤根:**皮肤中心真正在用的那个目录**下的 `skins`(见 skinCenterHome 的发现逻辑)。 */
|
|
43
|
+
function skinsRoot() { return join(skinCenterHome().root, 'skins'); }
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* **发现皮肤中心真正在用的那个数据目录**(而不是假定它就是我们的 `$DSH_HOME`)。
|
|
47
|
+
*
|
|
48
|
+
* 为什么必须发现:皮肤中心解析用户皮肤目录走的是它自己的 `resolveHarnessPaths()` ——
|
|
49
|
+
* 优先 `$DSH_HOME`,其次安装布局,**最后才是 `~/.dsh`**;而我们这边用的是
|
|
50
|
+
* `$DSH_HOME || %APPDATA%/dsh-desktop/harness`。两者在"便携安装 / 没设 DSH_HOME"的机器上
|
|
51
|
+
* 会指向**不同目录**:我们把皮肤装进 harness/skins,它却去 `~/.dsh/skins` 找 ⇒ 它列表里
|
|
52
|
+
* 只剩内置那一套,用户点哪套都无效(实测症状:只剩鲸鱼娘/blue-fantasy)。
|
|
53
|
+
*
|
|
54
|
+
* 判据不看猜:**它自己会把 `skin-center-active.json` 写在 `<它的用户皮肤目录>/..`**,
|
|
55
|
+
* 所以"哪个候选目录里存在这个文件、且最近被写过",那个就是它在用的目录。
|
|
56
|
+
* 拿不到任何线索时退回我们自己的目录(也就是今天的行为,不会更差)。
|
|
57
|
+
*/
|
|
58
|
+
const homeCache = { at: 0, value: null };
|
|
59
|
+
function skinCenterHome(force) {
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
if (!force && homeCache.value && now - homeCache.at < 30000) return homeCache.value;
|
|
62
|
+
const candidates = [];
|
|
63
|
+
const push = (root) => { if (root) candidates.push(root); };
|
|
64
|
+
push(dshHome());
|
|
65
|
+
push(join(homedir(), '.dsh'));
|
|
66
|
+
if (process.env.DSH_SKINS_DIR) push(join(process.env.DSH_SKINS_DIR, '..'));
|
|
67
|
+
let best = null;
|
|
68
|
+
for (const root of candidates) {
|
|
69
|
+
const statePath = join(root, 'skin-center-active.json');
|
|
70
|
+
const at = (() => { try { return statSync(statePath).mtimeMs; } catch { return 0; } })();
|
|
71
|
+
if (!best || at > best.at) best = { root, statePath, at };
|
|
72
|
+
}
|
|
73
|
+
// 没有任何 state 文件时,退回"我们的根":安装路径保持不变,行为与之前一致。
|
|
74
|
+
const chosen = (best && best.at > 0) ? best : { root: dshHome(), statePath: activeStatePathFallback(), at: 0 };
|
|
75
|
+
homeCache.at = now;
|
|
76
|
+
homeCache.value = chosen;
|
|
77
|
+
return chosen;
|
|
78
|
+
}
|
|
79
|
+
function activeStatePathFallback() { return join(dshHome(), 'skin-center-active.json'); }
|
|
44
80
|
|
|
45
81
|
/**
|
|
46
82
|
* 皮肤中心持久化"当前皮肤"的那个文件。
|
|
@@ -52,7 +88,7 @@ function skinsRoot() { return join(dshHome(), 'skins'); }
|
|
|
52
88
|
* 并且客户端每 2 秒轮询一次 GET 收敛 —— 所以写这个文件等价于"替它记下选择",可靠且即时。
|
|
53
89
|
* 语义上只改 `active` 一个键,其余原样保留。
|
|
54
90
|
*/
|
|
55
|
-
function activeStatePath() { return
|
|
91
|
+
function activeStatePath() { return skinCenterHome().statePath; }
|
|
56
92
|
|
|
57
93
|
/** 把 `active` 写进皮肤中心的持久层(保留其它字段;原子替换,失败不破坏原文件)。 */
|
|
58
94
|
function writeActiveStateFile(id) {
|
|
@@ -433,10 +469,11 @@ function normalizeSkinManifest(manifestPath, base) {
|
|
|
433
469
|
const cssPath = str(doc.contributes.stylesheet);
|
|
434
470
|
const cssExists = cssPath && (() => { try { return statSync(join(dir, cssPath)).isFile(); } catch { return false; } })();
|
|
435
471
|
if (!cssExists) {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
472
|
+
const pick = (() => {
|
|
473
|
+
try {
|
|
474
|
+
return readdirSync(dir).find((n) => n.toLowerCase().endsWith('.css') && statSync(join(dir, n)).isFile()) || '';
|
|
475
|
+
} catch { return ''; }
|
|
476
|
+
})();
|
|
440
477
|
if (pick) { doc.contributes.stylesheet = pick; fixes.push('stylesheet'); }
|
|
441
478
|
else { delete doc.contributes.stylesheet; fixes.push('stylesheet-missing'); }
|
|
442
479
|
}
|
|
@@ -518,6 +555,11 @@ export function registerSkinsRoutes(webServer, c) {
|
|
|
518
555
|
skinCenterDisabled: market.skinCenterDisabled,
|
|
519
556
|
skinCenterMarketKnown: market.known,
|
|
520
557
|
skinCenterDetail: skinCenterProbe.detail || '',
|
|
558
|
+
// 诊断用:我们**实际读写**的目录 vs 皮肤中心自己的数据根。
|
|
559
|
+
// 便携安装 / 未设 DSH_HOME 的机器上两者曾不一致(它去 `~/.dsh` 找,我们写进 harness)
|
|
560
|
+
// ⇒ 它的列表里只剩内置款、点哪套都无效。现在由 skinCenterHome() 发现并统一,这里透出结果。
|
|
561
|
+
skinsRoot: skinsRoot(),
|
|
562
|
+
skinCenterRoot: skinCenterHome().root,
|
|
521
563
|
// 版本线索:我们随身携带的是 0.4.12(engines 要求 dsh >= 0.2.1-rc.3)。
|
|
522
564
|
// 低于该内核的机器会被市场 keep off —— 页签据此告诉用户"要么升级桌面端、要么别指望它"。
|
|
523
565
|
skinCenterHint: skinCenter === 'present'
|