wallpaper-engine-dsh 1.0.7 → 1.0.8

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/README.md CHANGED
@@ -64,6 +64,7 @@ Media serving is defensive by design: tokens are unguessable 72-bit values, stab
64
64
 
65
65
  - Scene and application wallpapers are not listed: they are Wallpaper Engine's private `.pkg` scene packages, and their live animation can only be rendered by Wallpaper Engine itself on the desktop.
66
66
  - Web wallpapers run isolated from the page's storage, so ones that persist state across loads won't keep it.
67
+ - Web wallpapers with sound may stay silent until you interact with the page — browsers gate audio in sandboxed documents on a user gesture, and wallpapers that rely on Wallpaper Engine's system-audio feed (visualizers) have no signal to draw from.
67
68
  - The glass effect reads DSH design tokens; if a future shell redesign renames them, frosting degrades to plain transparency.
68
69
 
69
70
  ## Development
package/README.zh.md CHANGED
@@ -64,6 +64,7 @@ bundle 分为两半:
64
64
 
65
65
  - 场景与应用壁纸不出现在列表中:它们是 Wallpaper Engine 私有的 `.pkg` 场景包,动态渲染只能由桌面端的 Wallpaper Engine 完成。
66
66
  - 网页壁纸与页面存储隔离,需要跨加载保存状态的壁纸无法保留状态。
67
+ - 带声音的网页壁纸可能在你与页面交互前保持静默——浏览器对沙箱文档的音频有自动播放限制;依赖 Wallpaper Engine 系统音频输入的壁纸(如音频可视化)在浏览器中没有信号可画。
67
68
  - 玻璃效果读 DSH 设计令牌;若未来外壳重构重命名令牌,磨砂会退化为普通半透明。
68
69
 
69
70
  ## 开发
package/lib/client.js CHANGED
@@ -688,6 +688,7 @@ window.__ModuleLoader__.load({
688
688
  media = document.createElement("iframe");
689
689
  media.src = sel.url;
690
690
  media.setAttribute("sandbox", "allow-scripts");
691
+ media.setAttribute("allow", "autoplay");
691
692
  media.setAttribute("referrerpolicy", "no-referrer");
692
693
  media.setAttribute("frameborder", "0");
693
694
  media.setAttribute("scrolling", "no");
@@ -1019,7 +1020,13 @@ window.__ModuleLoader__.load({
1019
1020
  if (existing) {
1020
1021
  existing.classList.add("webg-layer--leave");
1021
1022
  const stale = existing;
1022
- schedule(() => stale.remove(), LEAVE_MS);
1023
+ schedule(() => {
1024
+ const v = stale.querySelector("video");
1025
+ if (v) { v.pause(); v.removeAttribute("src"); if (typeof v.load === "function") v.load(); }
1026
+ const f = stale.querySelector("iframe");
1027
+ if (f) { f.src = "about:blank"; }
1028
+ stale.remove();
1029
+ }, LEAVE_MS);
1023
1030
  }
1024
1031
  }
1025
1032
  const node = document.getElementById(LAYER_ID);
@@ -1035,11 +1042,18 @@ window.__ModuleLoader__.load({
1035
1042
  existing.classList.add("webg-layer--leave");
1036
1043
  const stale = existing;
1037
1044
  schedule(() => {
1045
+ const v = stale.querySelector("video");
1046
+ if (v) { v.pause(); v.removeAttribute("src"); if (typeof v.load === "function") v.load(); }
1047
+ const f = stale.querySelector("iframe");
1048
+ if (f) { f.src = "about:blank"; }
1038
1049
  stale.remove();
1039
1050
  if (!document.getElementById(LAYER_ID)) {
1040
1051
  const s = document.getElementById(SCRIM_ID);
1041
1052
  if (s) s.remove();
1042
1053
  document.body.removeAttribute(ACTIVE_ATTR);
1054
+ if (previewProbe) { previewProbe.remove(); previewProbe = null; }
1055
+ sampledLuminance = null;
1056
+ clearEffects();
1043
1057
  }
1044
1058
  }, LEAVE_MS);
1045
1059
  }
@@ -1060,6 +1074,9 @@ window.__ModuleLoader__.load({
1060
1074
  if (selection.type === "web") {
1061
1075
  const w = selection.inventory.wallpapers.find((x) => x.id === selection.id);
1062
1076
  if (w && w.preview) probePreviewLuminance(w.preview);
1077
+ } else if (previewProbe) {
1078
+ previewProbe.remove();
1079
+ previewProbe = null;
1063
1080
  }
1064
1081
  }
1065
1082
  }
@@ -1147,9 +1164,10 @@ window.__ModuleLoader__.load({
1147
1164
  // wallpapers, light theme (dark text) brightens dark ones — either way the
1148
1165
  // text side wins. This is what makes ANY wallpaper survivable.
1149
1166
  const dark = Boolean(document.body.hasAttribute && document.body.hasAttribute("data-ds-dark-theme"));
1167
+ const roundedLum = sampledLuminance !== null ? Math.round(sampledLuminance * 100) / 100 : null;
1150
1168
  const key = [
1151
1169
  dark, selection.scrim, selection.border, selection.blur, selection.wallpaperBlur,
1152
- selection.autoScrim, sampledLuminance, selection.fit, selection.zoom,
1170
+ selection.autoScrim, roundedLum, selection.fit, selection.zoom,
1153
1171
  selection.offsetX, selection.offsetY, selection.rotation, selection.mirrored,
1154
1172
  ].join("\u0000");
1155
1173
  if (key === lastEffectKey) return; // nothing it reads changed → no writes, no reflow
@@ -1200,9 +1218,6 @@ window.__ModuleLoader__.load({
1200
1218
  // slider feedback lands on this frame even on stalled compositors.
1201
1219
  const scrim = document.getElementById(SCRIM_ID);
1202
1220
  if (scrim) scrim.style.background = veilColor;
1203
- if (document.body && document.body.offsetHeight !== undefined) {
1204
- void document.body.offsetHeight;
1205
- }
1206
1221
  }
1207
1222
 
1208
1223
  function clearEffects() {
@@ -1242,7 +1257,7 @@ window.__ModuleLoader__.load({
1242
1257
  }
1243
1258
  onInput(v);
1244
1259
  };
1245
- return React.createElement(React.Fragment, null,
1260
+ return React.createElement(React.Fragment, { key: label },
1246
1261
  React.createElement("span", { className: "webg-hint webg-label" }, label),
1247
1262
  React.createElement("input", {
1248
1263
  className: "webg-slider", type: "range",
@@ -1446,6 +1461,7 @@ window.__ModuleLoader__.load({
1446
1461
  className: "webg-text webg-search", type: "search",
1447
1462
  placeholder: t.searchPlaceholder,
1448
1463
  value: query,
1464
+ onChange: (e) => setQuery(e.target.value),
1449
1465
  onInput: (e) => setQuery(e.target.value),
1450
1466
  }),
1451
1467
  query.trim() && React.createElement("span", { className: "webg-hint" },
@@ -1476,14 +1492,14 @@ window.__ModuleLoader__.load({
1476
1492
  React.createElement("span", { className: "webg-card-close" }, t.closeCard),
1477
1493
  ),
1478
1494
  usableList.length === 0
1479
- ? React.createElement("span", { className: "webg-hint" },
1495
+ ? React.createElement("span", { className: "webg-hint webg-grid-empty" },
1480
1496
  sel.inventory.installDir
1481
1497
  ? (sel.inventory.total > 0
1482
1498
  ? t.emptyNoUsable(sel.inventory.total)
1483
1499
  : t.emptyNoProjects)
1484
1500
  : t.emptyNoInstall)
1485
1501
  : filteredList.length === 0
1486
- ? React.createElement("span", { className: "webg-hint" }, t.noMatch(q))
1502
+ ? React.createElement("span", { className: "webg-hint webg-grid-empty" }, t.noMatch(q))
1487
1503
  : filteredList.map((w) => ThumbCard(w, w.id === sel.id, () => applySelection(w.id), t)),
1488
1504
  );
1489
1505
  }
@@ -1563,7 +1579,9 @@ window.__ModuleLoader__.load({
1563
1579
  React.createElement("input", {
1564
1580
  className: "webg-text", type: "text",
1565
1581
  value: editing.name,
1566
- onInput: (e) => { editing.name = e.target.value; emit(); },
1582
+ onChange: (e) => { editing.name = e.target.value; if (!e.nativeEvent || !e.nativeEvent.isComposing) emit(); },
1583
+ onInput: (e) => { editing.name = e.target.value; },
1584
+ onCompositionEnd: (e) => { editing.name = e.target.value; emit(); },
1567
1585
  }),
1568
1586
  ),
1569
1587
  React.createElement("div", { className: "webg-row" },
@@ -1588,6 +1606,7 @@ window.__ModuleLoader__.load({
1588
1606
  className: "webg-text", type: "search",
1589
1607
  placeholder: t.filterPlaceholder,
1590
1608
  value: editorQuery,
1609
+ onChange: (e) => setEditorQuery(e.target.value),
1591
1610
  onInput: (e) => setEditorQuery(e.target.value),
1592
1611
  }),
1593
1612
  React.createElement("div", { className: "webg-editor-grid" },
@@ -1595,10 +1614,10 @@ window.__ModuleLoader__.load({
1595
1614
  const eq = editorQuery.trim();
1596
1615
  const pool = usableList.filter((w) => matchesQuery(w, eq));
1597
1616
  if (usableList.length === 0) {
1598
- return React.createElement("span", { className: "webg-hint" }, t.noUsable);
1617
+ return React.createElement("span", { className: "webg-hint webg-grid-empty" }, t.noUsable);
1599
1618
  }
1600
1619
  if (pool.length === 0) {
1601
- return React.createElement("span", { className: "webg-hint" }, t.noMatch(eq));
1620
+ return React.createElement("span", { className: "webg-hint webg-grid-empty" }, t.noMatch(eq));
1602
1621
  }
1603
1622
  return pool.map((w) => EditorCard(w, editing, t));
1604
1623
  })(),
@@ -1685,7 +1704,7 @@ window.__ModuleLoader__.load({
1685
1704
  className: "webg-btn", type: "button", onClick: enterAdjust,
1686
1705
  disabled: sel.adjusting,
1687
1706
  }, t.adjust),
1688
- (sel.zoom !== 1 || sel.offsetX !== 0 || sel.offsetY !== 0) &&
1707
+ (sel.zoom !== 1 || sel.offsetX !== 0 || sel.offsetY !== 0 || sel.rotation !== 0) &&
1689
1708
  React.createElement("button", {
1690
1709
  className: "webg-btn", type: "button", onClick: resetCrop,
1691
1710
  }, t.resetCrop),
@@ -2070,6 +2089,11 @@ window.__ModuleLoader__.load({
2070
2089
  display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
2071
2090
  gap: 8px; max-height: 300px; overflow-y: auto; padding: 2px;
2072
2091
  }
2092
+ .webg-grid-empty {
2093
+ grid-column: 1 / -1;
2094
+ display: flex; align-items: center; justify-content: center;
2095
+ padding: 24px 12px; text-align: center;
2096
+ }
2073
2097
  .webg-card {
2074
2098
  position: relative; width: 100%; padding: 0; cursor: pointer;
2075
2099
  aspect-ratio: 16 / 9; display: block; overflow: hidden;
@@ -2323,7 +2347,7 @@ window.__ModuleLoader__.load({
2323
2347
  if (ctx.slots) {
2324
2348
  ctx.slots.inject("settings.general.item", () =>
2325
2349
  ctx.slots.register(
2326
- { name: "settings.general.item", id: "we-background", order: 500, label: S().settingsLabel },
2350
+ { name: "settings.general.item", id: "we-background", order: 500, label: () => S().settingsLabel },
2327
2351
  () => React.createElement(WallpaperPicker),
2328
2352
  ),
2329
2353
  );
package/lib/core.js CHANGED
@@ -174,8 +174,10 @@ export function steamProbeDirs(platform = process.platform, home = homedir) {
174
174
  return [
175
175
  'C:\\Program Files (x86)\\Steam',
176
176
  'C:\\Program Files\\Steam',
177
+ 'C:\\SteamLibrary',
177
178
  'D:\\Steam',
178
179
  'D:\\SteamLibrary',
180
+ 'E:\\Steam',
179
181
  'E:\\SteamLibrary',
180
182
  ];
181
183
  case 'darwin':
@@ -536,9 +538,13 @@ export function mimeFor(absPath) {
536
538
  js: 'text/javascript; charset=utf-8', mjs: 'text/javascript; charset=utf-8',
537
539
  css: 'text/css; charset=utf-8', json: 'application/json; charset=utf-8',
538
540
  jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif',
539
- png: 'image/png', webp: 'image/webp', svg: 'image/svg+xml',
541
+ png: 'image/png', webp: 'image/webp', svg: 'image/svg+xml', ico: 'image/x-icon',
540
542
  mp3: 'audio/mpeg', ogg: 'audio/ogg', wav: 'audio/wav',
543
+ flac: 'audio/flac', aac: 'audio/aac', m4a: 'audio/mp4',
541
544
  woff: 'font/woff', woff2: 'font/woff2', ttf: 'font/ttf',
545
+ otf: 'font/otf', eot: 'application/vnd.ms-fontobject',
546
+ wasm: 'application/wasm', txt: 'text/plain; charset=utf-8',
547
+ xml: 'application/xml; charset=utf-8',
542
548
  }[ext] || 'application/octet-stream';
543
549
  }
544
550
 
package/lib/index.js CHANGED
@@ -265,7 +265,7 @@ export function createRouteRegistrar(webServer, opts = {}) {
265
265
  // unguessable token remains the only capability — wildcard origin
266
266
  // grants nothing beyond what a known URL already grants.
267
267
  res.setHeader('Access-Control-Allow-Origin', '*');
268
- if (mime === 'text/html' || mime === 'image/svg+xml') {
268
+ if (mime.startsWith('text/html') || mime === 'image/svg+xml') {
269
269
  // Script-capable documents (web wallpapers, SVG previews) get a
270
270
  // sandbox CSP even on direct top-level navigation, so they can
271
271
  // never execute against the DSH origin. `allow-scripts` keeps the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wallpaper-engine-dsh",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Wallpaper Engine library as the DSH web GUI background — video/web/still wallpapers, rotation lists, search, resource monitor, bilingual UI.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",