dsh-vidi 0.7.9 → 0.8.0

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
@@ -34794,6 +34794,27 @@ function Settings(props) {
34794
34794
  const { engine, onEngine, mode, onMode, spoken, onSpoken, langOptions, login, onLogin, browsers, providers, shared, name, onKey, disabled, open, onOpen, update, onCheckUpdate, t } = props;
34795
34795
  const [checking, setChecking] = (0, react.useState)(false);
34796
34796
  const [checked, setChecked] = (0, react.useState)(false);
34797
+ const [installing, setInstalling] = (0, react.useState)(false);
34798
+ const [installed, setInstalled] = (0, react.useState)(null);
34799
+ const installUpdate = async () => {
34800
+ setInstalling(true);
34801
+ setInstalled(null);
34802
+ try {
34803
+ const j = await (await fetch("/live/api/update", {
34804
+ method: "POST",
34805
+ headers: { "content-type": "application/json" },
34806
+ body: "{}"
34807
+ })).json();
34808
+ setInstalled(j);
34809
+ if (j.status === "applied") setTimeout(() => location.reload(), 800);
34810
+ } catch (e) {
34811
+ setInstalled({
34812
+ status: "failed",
34813
+ message: e.message
34814
+ });
34815
+ }
34816
+ setInstalling(false);
34817
+ };
34797
34818
  const box = (0, react.useRef)(null);
34798
34819
  const [draft, setDraft] = (0, react.useState)("");
34799
34820
  const [busy, setBusy] = (0, react.useState)(false);
@@ -35127,9 +35148,14 @@ function Settings(props) {
35127
35148
  children: [
35128
35149
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
35129
35150
  className: "vline",
35130
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("upd.version").replace("{v}", update.current) }), update.newer ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
35151
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("upd.version").replace("{v}", update.current) }), update.newer ? update.canInstall && !installed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
35152
+ className: "dshl-btn primary small",
35153
+ disabled: installing,
35154
+ onClick: () => void installUpdate(),
35155
+ children: installing ? t("upd.installing") : t("upd.install").replace("{v}", update.latest ?? "")
35156
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
35131
35157
  className: "new",
35132
- children: t("upd.available").replace("{v}", update.latest ?? "")
35158
+ children: installed?.status === "restart" ? t("upd.restart").replace("{v}", installed.version ?? "") : installed?.status === "applied" ? t("upd.applied") : t("upd.available").replace("{v}", update.latest ?? "")
35133
35159
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
35134
35160
  className: "dshl-link",
35135
35161
  disabled: checking,
@@ -35143,10 +35169,18 @@ function Settings(props) {
35143
35169
  children: checking ? t("upd.checking") : checked && !update.error ? t("upd.latest") : t("upd.check")
35144
35170
  })]
35145
35171
  }),
35146
- update.newer && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
35172
+ update.newer && !update.canInstall && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
35147
35173
  className: "hint",
35148
35174
  children: t("upd.how")
35149
35175
  }),
35176
+ installed?.status === "restart" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
35177
+ className: "hint",
35178
+ children: t("upd.restartHow")
35179
+ }),
35180
+ installed?.status === "failed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
35181
+ className: "hint",
35182
+ children: t("upd.installFailed").replace("{m}", installed.message ?? "")
35183
+ }),
35150
35184
  checked && update.error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
35151
35185
  className: "hint",
35152
35186
  children: t("upd.failed")
@@ -37227,6 +37261,12 @@ const en = {
37227
37261
  "upd.latest": "Up to date",
37228
37262
  "upd.available": "Version {v} is out",
37229
37263
  "upd.how": "Update it from DSH’s Plugins page, then restart the app.",
37264
+ "upd.install": "Update to {v}",
37265
+ "upd.installing": "Updating…",
37266
+ "upd.restart": "{v} installed",
37267
+ "upd.restartHow": "Restart the app to use it.",
37268
+ "upd.applied": "Updated",
37269
+ "upd.installFailed": "The update did not go through ({m}). The Plugins page can update it too.",
37230
37270
  "upd.failed": "Could not reach npm just now; it checks again tomorrow.",
37231
37271
  "src.tip": "Where the video comes from",
37232
37272
  "src.link": "Link",
@@ -37652,6 +37692,12 @@ const zh = {
37652
37692
  "upd.latest": "已是最新",
37653
37693
  "upd.available": "有新版本 {v}",
37654
37694
  "upd.how": "到 DSH 的「插件」页面更新,再重启 app。",
37695
+ "upd.install": "更新到 {v}",
37696
+ "upd.installing": "正在更新…",
37697
+ "upd.restart": "{v} 已装好",
37698
+ "upd.restartHow": "重启 app 后生效。",
37699
+ "upd.applied": "已更新",
37700
+ "upd.installFailed": "这次没更新成({m}),也可以到「插件」页面更新。",
37655
37701
  "upd.failed": "这会儿连不上 npm,明天会再查一次。",
37656
37702
  "src.tip": "视频从哪里来",
37657
37703
  "src.link": "链接",
@@ -38528,6 +38574,7 @@ body > .dshl-menu { z-index: 2147483002; }
38528
38574
  .dshl-pop.settings .srow + .srow { border-top: 1px solid var(--line-soft); }
38529
38575
  .dshl-pop.settings .srow.version .vline { display: flex; align-items: center; justify-content: space-between; gap: 12px; width: 100%; color: var(--faint); font-size: 12.5px; }
38530
38576
  .dshl-pop.settings .srow.version .new { color: #e5484d; font-weight: 550; }
38577
+ .dshl-pop.settings .srow.version .dshl-btn.small { height: 28px; padding: 0 12px; border-radius: 7px; font-size: 12.5px; }
38531
38578
  .dshl-pop.settings .srow > .dshl-select, .dshl-pop.settings .srow > .dshl-seg { width: 168px; }
38532
38579
  .dshl-pop.settings .srow > .dshl-seg button { flex: 1; padding: 0 6px; }
38533
38580
  .dshl .srow.col { display: grid; justify-content: stretch; gap: 8px; padding: 10px 0; }
package/lib/index.mjs CHANGED
@@ -5780,6 +5780,9 @@ function metered(llm, meter) {
5780
5780
  }
5781
5781
  // src/updates.ts
5782
5782
  const DAY = 864e5;
5783
+ /** pnpm holds back releases younger than a day: offer only versions it will install. */
5784
+ const MIN_AGE = process.env.VIDI_UPDATE_MIN_AGE_HOURS !== void 0 ? Number(process.env.VIDI_UPDATE_MIN_AGE_HOURS) * 36e5 : DAY;
5785
+ const NAME = "dsh-vidi";
5783
5786
  /** a > b for plain x.y.z versions (pre-releases count as older than the release). */
5784
5787
  function greater(a, b) {
5785
5788
  const parse = (v) => {
@@ -5793,38 +5796,76 @@ function greater(a, b) {
5793
5796
  for (let i = 0; i < 3; i++) if ((x.n[i] ?? 0) !== (y.n[i] ?? 0)) return (x.n[i] ?? 0) > (y.n[i] ?? 0);
5794
5797
  return !x.pre && !!y.pre;
5795
5798
  }
5796
- function updateChecker(log) {
5799
+ function updateChecker(log, manager) {
5797
5800
  let current = "0.0.0";
5798
5801
  try {
5799
5802
  current = String(JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version);
5800
5803
  } catch {}
5801
5804
  let latest, checkedAt, error;
5805
+ let canInstall = false;
5802
5806
  let running;
5803
5807
  const state = () => ({
5804
5808
  current,
5805
5809
  latest,
5806
5810
  newer: !!latest && greater(latest, current),
5811
+ canInstall,
5807
5812
  checkedAt,
5808
5813
  error
5809
5814
  });
5810
5815
  const check = () => running ??= (async () => {
5811
5816
  try {
5812
- const r = await fetch("https://registry.npmjs.org/dsh-vidi/latest", {
5813
- signal: AbortSignal.timeout(1e4),
5817
+ const r = await fetch(`https://registry.npmjs.org/${NAME}`, {
5818
+ signal: AbortSignal.timeout(15e3),
5814
5819
  headers: { accept: "application/json" }
5815
5820
  });
5816
5821
  if (!r.ok) throw new Error(`registry ${r.status}`);
5817
- latest = String((await r.json()).version ?? "") || void 0;
5822
+ const doc = await r.json();
5823
+ latest = Object.keys(doc.versions ?? {}).filter((v) => !v.includes("-") && Date.now() - Date.parse(doc.time?.[v] ?? "") >= MIN_AGE).reduce((best, v) => !best || greater(v, best) ? v : best, void 0);
5818
5824
  error = void 0;
5819
5825
  if (latest && greater(latest, current)) log(`update: ${latest} available (running ${current})`);
5820
5826
  } catch (err) {
5821
5827
  error = err.message;
5822
- } finally {
5823
- checkedAt = Date.now();
5824
- running = void 0;
5825
5828
  }
5829
+ try {
5830
+ canInstall = !!(await manager()?.listBundles())?.find((b) => b.name === NAME)?.updatable;
5831
+ } catch {
5832
+ canInstall = false;
5833
+ }
5834
+ checkedAt = Date.now();
5835
+ running = void 0;
5826
5836
  return state();
5827
5837
  })();
5838
+ /** Install the newest version through DSH's plugin manager. */
5839
+ const install = async () => {
5840
+ const pm = manager();
5841
+ if (!pm || !latest || !greater(latest, current)) return {
5842
+ status: "failed",
5843
+ message: "nothing to install"
5844
+ };
5845
+ log(`update: installing ${latest}`);
5846
+ try {
5847
+ const out = await pm.updateBundle(NAME, latest, { requestId: `vidi-update-${Date.now()}` });
5848
+ const app = out.result?.application;
5849
+ if (app === "restart-required") return {
5850
+ status: "restart",
5851
+ version: latest
5852
+ };
5853
+ if (app === "applied" || app === "unchanged") return {
5854
+ status: "applied",
5855
+ version: latest
5856
+ };
5857
+ const e = out.result?.error;
5858
+ return {
5859
+ status: "failed",
5860
+ message: e?.diagnostic || e?.message || e?.code || app || "failed"
5861
+ };
5862
+ } catch (err) {
5863
+ return {
5864
+ status: "failed",
5865
+ message: err.message
5866
+ };
5867
+ }
5868
+ };
5828
5869
  check();
5829
5870
  const timer = setInterval(() => void check(), DAY);
5830
5871
  timer.unref?.();
@@ -5834,6 +5875,7 @@ function updateChecker(log) {
5834
5875
  return state();
5835
5876
  },
5836
5877
  check,
5878
+ install,
5837
5879
  stop: () => clearInterval(timer)
5838
5880
  };
5839
5881
  }
@@ -6449,6 +6491,7 @@ function apply(ctx, config) {
6449
6491
  return send(res, 200, job.summary());
6450
6492
  }
6451
6493
  if (route === "version") return send(res, 200, req.method === "POST" ? await updates.check() : updates.state());
6494
+ if (route === "update" && req.method === "POST") return send(res, 200, await updates.install());
6452
6495
  if (route === "devices") {
6453
6496
  const devices = await listDevices();
6454
6497
  log(`devices: ${devices.filter((d) => d.kind !== "mic").length} picture, ${devices.filter((d) => d.kind === "mic").length} microphone`);
@@ -6890,7 +6933,13 @@ function apply(ctx, config) {
6890
6933
  }), "dsh-vidi: media route");
6891
6934
  let updates;
6892
6935
  ctx.effect(() => {
6893
- updates = updateChecker(log);
6936
+ updates = updateChecker(log, () => {
6937
+ try {
6938
+ return ctx.get?.("pluginManager");
6939
+ } catch {
6940
+ return;
6941
+ }
6942
+ });
6894
6943
  return () => updates.stop();
6895
6944
  }, "dsh-vidi: update check");
6896
6945
  ctx.effect(() => startOverlay(config.overlayPort, () => [...jobs.values()].filter((j) => j.summary().status === "running").at(-1) ?? [...jobs.values()].at(-1), (fn) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-vidi",
3
- "version": "0.7.9",
3
+ "version": "0.8.0",
4
4
  "description": "A video tool for DeepSeek Harness: watch live streams, videos and podcasts with real-time subtitles in any language, then clip and download",
5
5
  "type": "module",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",