dsh-mpkg-wallpaper 3.15.6 → 3.15.7

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.
Files changed (2) hide show
  1. package/lib/client.js +83 -7
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -1479,6 +1479,17 @@ function sectionSigNow() {
1479
1479
  } catch (e) {}
1480
1480
  return "";
1481
1481
  }
1482
+ /* ②(2026-10-05 真机残留复核) `sceneKey` 是**粘性源字段**之一:换档/自愈之后它可能还挂着
1483
+ 上一个场景的值(真机现场:`converted="mp4"` 的 mpkg 档里仍留着 `scene|probe|…/scene.pkg`)。
1484
+ 今天它无害(挂载只在 `converted === "scene"` 时看它),但它是"哪天被别的分支读到就翻盘"的
1485
+ 典型地雷 ⇒ 自愈写回时**显式删掉**(`null` 是唯一会被 sticky 护栏尊重的删除语义)。 */
1486
+ function mpwStripForeignSceneKey(sec) {
1487
+ try {
1488
+ const out = Object.assign({}, sec || {});
1489
+ if (String(out.converted || "") !== "scene" && out.sceneKey) out.sceneKey = null;
1490
+ return out;
1491
+ } catch (e) { return sec }
1492
+ }
1482
1493
  /** 档里是不是"只剩 image token、身份/类型全空"(真机那条半残档的形状)。 */
1483
1494
  function mpwIdentityMissing(s) {
1484
1495
  try {
@@ -2553,7 +2564,7 @@ function mpwThumbFail(el, why) {
2553
2564
  if (MPW_HEAL.last && MPW_HEAL.last.ok && MPW_HEAL.last.key === key && mpwVal(cur, "image") !== void 0) return false;
2554
2565
  const bak = mpwBackupSrc();
2555
2566
  if (bak && MPW_SRC_KEYS.some((sk) => typeof bak[sk] === "string" && bak[sk])) {
2556
- const next = mpwMergeSection(cur, bak);
2567
+ const next = mpwStripForeignSceneKey(mpwMergeSection(cur, bak));
2557
2568
  writeSection(next, true);
2558
2569
  changed = true;
2559
2570
  MPW_HEAL.attempted++;
@@ -2573,7 +2584,7 @@ function mpwThumbFail(el, why) {
2573
2584
  try { nowKey = String(readSection().mpkgKey || "") } catch {}
2574
2585
  if (nowKey !== key) { try { console.warn("[dsh-mpkg-wallpaper] 自愈完成时壁纸已切换,丢弃迟到结果:", key); } catch {} return }
2575
2586
  if (found) {
2576
- writeSection(mpwMergeSection(readSection(), found), true);
2587
+ writeSection(mpwStripForeignSceneKey(mpwMergeSection(readSection(), found)), true);
2577
2588
  MPW_HEAL.healed++;
2578
2589
  MPW_HEAL.last = { key, ok: true, from: "derive", at: Date.now() };
2579
2590
  mpwTrace("settings:heal", { key, from: "derive" });
@@ -11811,6 +11822,7 @@ function mpwThumbFail(el, why) {
11811
11822
  keyFromImageToken: (img) => mpwKeyFromImageToken(img),
11812
11823
  healState: () => { try { return Object.assign({}, MPW_HEAL) } catch (e) { return {} } },
11813
11824
  identityMissing: (s) => mpwIdentityMissing(s || readSection()),
11825
+ stripForeignSceneKey: (s) => mpwStripForeignSceneKey(s || readSection()),
11814
11826
  deriveFromKey: (key) => mpwDeriveSourceFromKey(key || readSection().mpkgKey),
11815
11827
  heal: () => { try { return mpwHealHalfArchive() } catch (e) { return String(e && e.message || e) } },
11816
11828
  healState: () => Object.assign({}, MPW_HEAL, { last: MPW_HEAL.last ? Object.assign({}, MPW_HEAL.last) : null, sig: mpwHealSig }),
@@ -18102,6 +18114,10 @@ ${popSurfaceSel} {
18102
18114
  有宿主玻璃的弹层(标题栏子代理展开框 / VS Code 菜单 / 模型选择…)一个像素都不动。
18103
18115
  独立 token:--mpw-pop-surface(-dark)(不再共用面板表面 token --mpw-surface-pop)。 */
18104
18116
  html body [data-mpw-pop-bg] { background-color: var(--mpw-pop-surface) !important; }
18117
+ /* ②(2026-10-05) 弹层处在一个"自己有底的玻璃祖先"里面(backdrop root 被截断 ⇒ 我们糊不到页面背后):
18118
+ 与其"半透明却没模糊"(真机被读成"只有白色滤镜"),不如**做实在**——表面不透明度抬到 88%,
18119
+ 并把 backdrop-filter 撤掉(白算一遍)。注意:只动我们自己的标记属性,宿主元素一个都不碰。 */
18120
+ html body [data-mpw-pop-trunc] { background-color: color-mix(in srgb, var(--dsw-specific-sidebar-fill) 88%, transparent) !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; }
18105
18121
  html body[data-ds-dark-theme] [data-mpw-pop-bg] { background-color: var(--mpw-pop-surface-dark) !important; }
18106
18122
  [role="menu"] [class*="card"],
18107
18123
  [role="tooltip"] [class*="card"] {
@@ -24666,11 +24682,37 @@ body[data-mpw-modal] [role="dialog"] {
24666
24682
  getAnimations 只读动画表、不触发布局,闸门本身廉价。 */
24667
24683
  let mpwHeavyRecheckTimer = 0;
24668
24684
  const mpwHeavyPending = new Map();
24685
+ /* ②(2026-10-05 真机回归修复) 闸门的判据必须是"**真的在跑、而且会跑完**的动画":
24686
+ 旧写法 `document.getAnimations().length > 0` 把**任何**留在动画表里的条目都算成"在动画",
24687
+ 包括 `playState === 'finished'`(CSS 动画带 fill: forwards 会一直留着)与
24688
+ `iterations === Infinity`(光标闪烁/转圈这类**永不结束**的动画)⇒ 真机上只要页面里有
24689
+ 一个循环动画,闸门就**永久**登记、永不放行 ⇒ 弹层兜底底标记/右栏最外层标记/侧栏抑制
24690
+ 这些活全被饿死(真机读数:四个弹层都不再带 data-mpw-pop-bg,只剩宿主自己的不透明白底
24691
+ + 我们的 blur = "白色滤镜、没有玻璃")。
24692
+ 现在:① 只认 `running`;② 跳过无限循环动画(它们不会结束,不能拿它们当"稍后再跑"的理由);
24693
+ ③ 兜底——连续推迟超过 MPW_HEAVY_MAX_DEFER 次就**无条件放行一次**(宁可多跑一次重活,
24694
+ 也不能让功能被永久饿死)。 */
24695
+ const MPW_HEAVY_MAX_DEFER = 3;
24696
+ let mpwHeavyDeferStreak = 0;
24669
24697
  function mpwHeavyAnimRunning() {
24670
- try { return !!(document.getAnimations && document.getAnimations().length) } catch (e) { return false }
24698
+ try {
24699
+ if (!document.getAnimations) return false;
24700
+ const list = document.getAnimations();
24701
+ for (const a of list) {
24702
+ try {
24703
+ if (!a || a.playState !== "running") continue; // finished/paused/idle 一律不算
24704
+ const t = a.effect && a.effect.getTiming ? a.effect.getTiming() : null;
24705
+ if (t && t.iterations === Infinity) continue; // 永不结束的循环动画:不能当等待理由
24706
+ return true;
24707
+ } catch (e) { /* 单个动画读不到就跳过它 */ }
24708
+ }
24709
+ return false;
24710
+ } catch (e) { return false }
24671
24711
  }
24672
24712
  function mpwHeavyGate(name, fn) {
24673
- if (!mpwHeavyAnimRunning()) return true;
24713
+ if (!mpwHeavyAnimRunning()) { mpwHeavyDeferStreak = 0; return true; }
24714
+ if (mpwHeavyDeferStreak >= MPW_HEAVY_MAX_DEFER) { mpwHeavyDeferStreak = 0; return true; }
24715
+ mpwHeavyDeferStreak++;
24674
24716
  mpwHeavyPending.set(name, fn);
24675
24717
  if (!mpwHeavyRecheckTimer) {
24676
24718
  mpwHeavyRecheckTimer = setTimeout(() => {
@@ -24949,24 +24991,39 @@ body[data-mpw-modal] [role="dialog"] {
24949
24991
  try {
24950
24992
  const surfaces = document.querySelectorAll("[data-mpw-pop-bg]");
24951
24993
  const targets = new Set();
24994
+ const truncated = new Set();
24952
24995
  for (let i = 0; i < surfaces.length; i++) {
24953
24996
  const el = surfaces[i];
24954
24997
  let cs = null;
24955
24998
  try { cs = getComputedStyle(el) } catch (e) {}
24956
24999
  /* 硬前提(与 mpwTagPopoverBg 同口径):我们真的给了模糊才值得摘祖先的截断 */
24957
25000
  if (!cs || !cs.backdropFilter || String(cs.backdropFilter).indexOf("blur") < 0) continue;
25001
+ let blockedByGlass = false;
24958
25002
  for (let p = el.parentElement, n = 0; p && p !== document.body && p !== document.documentElement && n < 12; p = p.parentElement, n++) {
24959
25003
  let acs = null;
24960
25004
  try { acs = getComputedStyle(p) } catch (e) { break }
24961
- if (acs && acs.backdropFilter && acs.backdropFilter !== "none" && String(acs.backdropFilter).indexOf("blur") >= 0) { targets.add(p); break }
25005
+ const ablur = acs && acs.backdropFilter && acs.backdropFilter !== "none" && String(acs.backdropFilter).indexOf("blur") >= 0;
25006
+ if (!ablur) continue;
25007
+ /* ②(2026-10-05 真机回归) **祖先自己是"看得见的玻璃板"时绝不动它**:
25008
+ 它是用户能看到的那层模糊(真机现场:子代理展开框/输入框卡片被我们摘掉 blur 之后
25009
+ "模糊背景没有了"——正是之前夸过的那处效果)。判据 = 它有可见底色(α ≥ 0.05)。
25010
+ 这种情况下改为把**弹层自己的表面做实在**(不能糊到页面背后,就别假装是玻璃)。 */
25011
+ if (mpwColorAlpha(acs.backgroundColor) >= 0.05) { blockedByGlass = true; break }
25012
+ targets.add(p);
25013
+ break;
24962
25014
  }
25015
+ if (blockedByGlass) truncated.add(el);
24963
25016
  }
24964
25017
  const stale = document.querySelectorAll("[data-mpw-pop-untrunc]");
24965
25018
  for (let i = 0; i < stale.length; i++) { const el = stale[i]; if (!targets.has(el)) { try { el.removeAttribute("data-mpw-pop-untrunc") } catch (e) {} } }
24966
25019
  for (const el of targets) { if (!el.hasAttribute("data-mpw-pop-untrunc")) { try { el.setAttribute("data-mpw-pop-untrunc", "") } catch (e) {} } }
25020
+ /* 被"有底的玻璃祖先"挡住的那批:标记在**弹层自己**身上(绝不碰宿主元素),由 CSS 给实底 */
25021
+ const staleT = document.querySelectorAll("[data-mpw-pop-trunc]");
25022
+ for (let i = 0; i < staleT.length; i++) { const el = staleT[i]; if (!truncated.has(el)) { try { el.removeAttribute("data-mpw-pop-trunc") } catch (e) {} } }
25023
+ for (const el of truncated) { if (!el.hasAttribute("data-mpw-pop-trunc")) { try { el.setAttribute("data-mpw-pop-trunc", "") } catch (e) {} } }
24967
25024
  if (targets.size) mpwPopUntruncStyle();
24968
25025
  else if (popUntruncStyleEl && popUntruncStyleEl.parentElement) { try { popUntruncStyleEl.remove() } catch (e) {} popUntruncStyleEl = null; }
24969
- return targets.size;
25026
+ return targets.size + truncated.size * 1000; // 千位段 = 被"有底玻璃祖先"挡住、改为实底的弹层数
24970
25027
  } catch (e) { return 0 }
24971
25028
  }
24972
25029
  /* ①(P3) 判据出口(tools/popover-untrunc-test.mjs 直接调 sync 断言 打标/还原/硬前提/首截断者)。 */
@@ -24977,6 +25034,24 @@ body[data-mpw-modal] [role="dialog"] {
24977
25034
  };
24978
25035
  } catch (e) {}
24979
25036
 
25037
+ /* ②(2026-10-05) 探针/判据出口:弹层兜底底标记与"摘截断"两件事可被**手动触发并读回**——
25038
+ 真机排障要能区分"根本没跑"(调度被饿死、observer 没接上)与"跑了但条件不满足"(宿主
25039
+ 自己画了不透明白底/面积超阈值…)。只读+幂等,不改变任何语义。 */
25040
+ try {
25041
+ globalThis.__mpwPopTagTest = {
25042
+ run: () => { try { return mpwTagPopoverBg() } catch (e) { return -1 } },
25043
+ untrunc: () => { try { return mpwPopUntruncSync() } catch (e) { return -1 } },
25044
+ state: (sel) => {
25045
+ try {
25046
+ const el = document.querySelector(sel || "[data-mpw-pop-bg]");
25047
+ if (!el) return null;
25048
+ const cs = getComputedStyle(el);
25049
+ return { cls: String(el.className).slice(0, 60), tag: el.hasAttribute("data-mpw-pop-bg"), bg: cs.backgroundColor, bf: cs.backdropFilter, display: cs.display, vis: cs.visibility };
25050
+ } catch (e) { return null }
25051
+ },
25052
+ };
25053
+ } catch (e) {}
25054
+
24980
25055
  function setupPopTagWatch() {
24981
25056
  if (popTagWatch !== null) return;
24982
25057
  let praf = 0;
@@ -25069,7 +25144,8 @@ body[data-mpw-modal] [role="dialog"] {
25069
25144
  动画停 ⇒ 补跑执行、账目清空)。 */
25070
25145
  try {
25071
25146
  globalThis.__mpwHeavyTest = {
25072
- state: () => ({ pending: Array.from(mpwHeavyPending.keys()), timer: !!mpwHeavyRecheckTimer }),
25147
+ state: () => ({ pending: Array.from(mpwHeavyPending.keys()), timer: !!mpwHeavyRecheckTimer, streak: mpwHeavyDeferStreak }),
25148
+ animRunning: () => mpwHeavyAnimRunning(),
25073
25149
  gate: (name, fn) => mpwHeavyGate(name, fn),
25074
25150
  flushNow: () => {
25075
25151
  if (mpwHeavyRecheckTimer) { try { clearTimeout(mpwHeavyRecheckTimer) } catch (e) {} mpwHeavyRecheckTimer = 0; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-mpkg-wallpaper",
3
- "version": "3.15.6",
3
+ "version": "3.15.7",
4
4
  "description": "DSH Web 壁纸引擎 Wallpaper Engine mpkg 背景插件:浏览器内直接解析 .mpkg(preview.gif 动态背景/内嵌 mp4 视频/多时段切换),整屏统一虚化/对话框/弹层/遮罩独立虚化、镜头缩放平移、时钟、冲突检测。",
5
5
  "private": false,
6
6
  "type": "module",