dsh-vidi 0.7.8 → 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 +112 -4
- package/lib/index.mjs +114 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -34790,9 +34790,31 @@ async function post$1(path, body) {
|
|
|
34790
34790
|
if (!r.ok) throw new Error(j.error ?? `HTTP ${r.status}`);
|
|
34791
34791
|
return j;
|
|
34792
34792
|
}
|
|
34793
|
-
/** Everything most people never touch, behind one gear: recognition and its key, mode, spoken language, site login. */
|
|
34794
34793
|
function Settings(props) {
|
|
34795
|
-
const { engine, onEngine, mode, onMode, spoken, onSpoken, langOptions, login, onLogin, browsers, providers, shared, name, onKey, disabled, open, onOpen, t } = props;
|
|
34794
|
+
const { engine, onEngine, mode, onMode, spoken, onSpoken, langOptions, login, onLogin, browsers, providers, shared, name, onKey, disabled, open, onOpen, update, onCheckUpdate, t } = props;
|
|
34795
|
+
const [checking, setChecking] = (0, react.useState)(false);
|
|
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
|
+
};
|
|
34796
34818
|
const box = (0, react.useRef)(null);
|
|
34797
34819
|
const [draft, setDraft] = (0, react.useState)("");
|
|
34798
34820
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
@@ -34890,9 +34912,9 @@ function Settings(props) {
|
|
|
34890
34912
|
className: "dshl-pick",
|
|
34891
34913
|
ref: box,
|
|
34892
34914
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
34893
|
-
className: `dshl-ctl icon ${open ? "on" : ""}`,
|
|
34915
|
+
className: `dshl-ctl icon ${open ? "on" : ""} ${update?.newer ? "dot" : ""}`,
|
|
34894
34916
|
onClick: () => onOpen(!open),
|
|
34895
|
-
title: t("in.settings"),
|
|
34917
|
+
title: update?.newer ? t("upd.available").replace("{v}", update.latest ?? "") : t("in.settings"),
|
|
34896
34918
|
"aria-expanded": open,
|
|
34897
34919
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon.gear, {})
|
|
34898
34920
|
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -35120,6 +35142,50 @@ function Settings(props) {
|
|
|
35120
35142
|
}
|
|
35121
35143
|
]
|
|
35122
35144
|
})]
|
|
35145
|
+
}),
|
|
35146
|
+
update && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
35147
|
+
className: "srow col version",
|
|
35148
|
+
children: [
|
|
35149
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
35150
|
+
className: "vline",
|
|
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", {
|
|
35157
|
+
className: "new",
|
|
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 ?? "")
|
|
35159
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
35160
|
+
className: "dshl-link",
|
|
35161
|
+
disabled: checking,
|
|
35162
|
+
onClick: () => {
|
|
35163
|
+
setChecking(true);
|
|
35164
|
+
onCheckUpdate?.().finally(() => {
|
|
35165
|
+
setChecking(false);
|
|
35166
|
+
setChecked(true);
|
|
35167
|
+
});
|
|
35168
|
+
},
|
|
35169
|
+
children: checking ? t("upd.checking") : checked && !update.error ? t("upd.latest") : t("upd.check")
|
|
35170
|
+
})]
|
|
35171
|
+
}),
|
|
35172
|
+
update.newer && !update.canInstall && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
35173
|
+
className: "hint",
|
|
35174
|
+
children: t("upd.how")
|
|
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
|
+
}),
|
|
35184
|
+
checked && update.error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
35185
|
+
className: "hint",
|
|
35186
|
+
children: t("upd.failed")
|
|
35187
|
+
})
|
|
35188
|
+
]
|
|
35123
35189
|
})
|
|
35124
35190
|
]
|
|
35125
35191
|
})]
|
|
@@ -35389,6 +35455,15 @@ function LiveView(props) {
|
|
|
35389
35455
|
const linesBox = (0, react.useRef)(null);
|
|
35390
35456
|
const fileInput = (0, react.useRef)(null);
|
|
35391
35457
|
const active = !!job && (job.status === "resolving" || job.status === "running" || job.status === "stopping");
|
|
35458
|
+
const [update, setUpdate] = (0, react.useState)();
|
|
35459
|
+
(0, react.useEffect)(() => {
|
|
35460
|
+
fetch("/live/api/version").then((r) => r.ok ? r.json() : void 0).then(setUpdate).catch(() => {});
|
|
35461
|
+
}, []);
|
|
35462
|
+
const checkUpdate = async () => {
|
|
35463
|
+
try {
|
|
35464
|
+
setUpdate(await post("version", {}));
|
|
35465
|
+
} catch {}
|
|
35466
|
+
};
|
|
35392
35467
|
const [srcTab, setSrcTabRaw] = (0, react.useState)("link");
|
|
35393
35468
|
const setSrcTab = (v) => {
|
|
35394
35469
|
setSrcTabRaw(v);
|
|
@@ -36230,6 +36305,8 @@ function LiveView(props) {
|
|
|
36230
36305
|
},
|
|
36231
36306
|
open: settingsOpen,
|
|
36232
36307
|
onOpen: setSettingsOpen,
|
|
36308
|
+
update,
|
|
36309
|
+
onCheckUpdate: checkUpdate,
|
|
36233
36310
|
t
|
|
36234
36311
|
})
|
|
36235
36312
|
] });
|
|
@@ -37178,6 +37255,19 @@ const en = {
|
|
|
37178
37255
|
"note.noModel": "No model set up, so subtitles stay in the original language.",
|
|
37179
37256
|
"note.install": "Install first:",
|
|
37180
37257
|
"push.title": "Stream here from OBS",
|
|
37258
|
+
"upd.version": "Vidi {v}",
|
|
37259
|
+
"upd.check": "Check for updates",
|
|
37260
|
+
"upd.checking": "Checking…",
|
|
37261
|
+
"upd.latest": "Up to date",
|
|
37262
|
+
"upd.available": "Version {v} is out",
|
|
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.",
|
|
37270
|
+
"upd.failed": "Could not reach npm just now; it checks again tomorrow.",
|
|
37181
37271
|
"src.tip": "Where the video comes from",
|
|
37182
37272
|
"src.link": "Link",
|
|
37183
37273
|
"src.file": "Local file",
|
|
@@ -37596,6 +37686,19 @@ const zh = {
|
|
|
37596
37686
|
"note.noModel": "还没配置模型,字幕只显示原文",
|
|
37597
37687
|
"note.install": "需要先安装:",
|
|
37598
37688
|
"push.title": "用 OBS 推流到这里",
|
|
37689
|
+
"upd.version": "Vidi {v}",
|
|
37690
|
+
"upd.check": "检查更新",
|
|
37691
|
+
"upd.checking": "正在检查…",
|
|
37692
|
+
"upd.latest": "已是最新",
|
|
37693
|
+
"upd.available": "有新版本 {v}",
|
|
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}),也可以到「插件」页面更新。",
|
|
37701
|
+
"upd.failed": "这会儿连不上 npm,明天会再查一次。",
|
|
37599
37702
|
"src.tip": "视频从哪里来",
|
|
37600
37703
|
"src.link": "链接",
|
|
37601
37704
|
"src.file": "本地文件",
|
|
@@ -37989,6 +38092,8 @@ const CSS = `
|
|
|
37989
38092
|
background: var(--l1); color: var(--muted); font-size: 13px; cursor: pointer; }
|
|
37990
38093
|
.dshl-ctl.icon { width: 40px; padding: 0; }
|
|
37991
38094
|
.dshl-ctl.icon svg { width: 18px; height: 18px; }
|
|
38095
|
+
.dshl-ctl.icon.dot { position: relative; }
|
|
38096
|
+
.dshl-ctl.icon.dot::after { content: ''; position: absolute; top: 8px; right: 8px; width: 7px; height: 7px; border-radius: 50%; background: #e5484d; box-shadow: 0 0 0 2px var(--bg); }
|
|
37992
38097
|
.dshl-ctl:hover, .dshl-ctl.on { background: var(--hover); color: var(--ink); }
|
|
37993
38098
|
|
|
37994
38099
|
.dshl-note { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 12px 20px 0; padding: 9px 14px; border: 1px solid var(--line); border-radius: 10px;
|
|
@@ -38467,6 +38572,9 @@ body > .dshl-menu { z-index: 2147483002; }
|
|
|
38467
38572
|
.dshl .srow .duo { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: 8px; }
|
|
38468
38573
|
.dshl .srow .duo > .dshl-select { width: 100%; }
|
|
38469
38574
|
.dshl-pop.settings .srow + .srow { border-top: 1px solid var(--line-soft); }
|
|
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; }
|
|
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; }
|
|
38470
38578
|
.dshl-pop.settings .srow > .dshl-select, .dshl-pop.settings .srow > .dshl-seg { width: 168px; }
|
|
38471
38579
|
.dshl-pop.settings .srow > .dshl-seg button { flex: 1; padding: 0 6px; }
|
|
38472
38580
|
.dshl .srow.col { display: grid; justify-content: stretch; gap: 8px; padding: 10px 0; }
|
package/lib/index.mjs
CHANGED
|
@@ -5778,6 +5778,107 @@ function metered(llm, meter) {
|
|
|
5778
5778
|
}
|
|
5779
5779
|
};
|
|
5780
5780
|
}
|
|
5781
|
+
// src/updates.ts
|
|
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";
|
|
5786
|
+
/** a > b for plain x.y.z versions (pre-releases count as older than the release). */
|
|
5787
|
+
function greater(a, b) {
|
|
5788
|
+
const parse = (v) => {
|
|
5789
|
+
const [core = "", pre] = v.split("-");
|
|
5790
|
+
return {
|
|
5791
|
+
n: core.split(".").map((x) => Number(x) || 0),
|
|
5792
|
+
pre
|
|
5793
|
+
};
|
|
5794
|
+
};
|
|
5795
|
+
const x = parse(a), y = parse(b);
|
|
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);
|
|
5797
|
+
return !x.pre && !!y.pre;
|
|
5798
|
+
}
|
|
5799
|
+
function updateChecker(log, manager) {
|
|
5800
|
+
let current = "0.0.0";
|
|
5801
|
+
try {
|
|
5802
|
+
current = String(JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version);
|
|
5803
|
+
} catch {}
|
|
5804
|
+
let latest, checkedAt, error;
|
|
5805
|
+
let canInstall = false;
|
|
5806
|
+
let running;
|
|
5807
|
+
const state = () => ({
|
|
5808
|
+
current,
|
|
5809
|
+
latest,
|
|
5810
|
+
newer: !!latest && greater(latest, current),
|
|
5811
|
+
canInstall,
|
|
5812
|
+
checkedAt,
|
|
5813
|
+
error
|
|
5814
|
+
});
|
|
5815
|
+
const check = () => running ??= (async () => {
|
|
5816
|
+
try {
|
|
5817
|
+
const r = await fetch(`https://registry.npmjs.org/${NAME}`, {
|
|
5818
|
+
signal: AbortSignal.timeout(15e3),
|
|
5819
|
+
headers: { accept: "application/json" }
|
|
5820
|
+
});
|
|
5821
|
+
if (!r.ok) throw new Error(`registry ${r.status}`);
|
|
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);
|
|
5824
|
+
error = void 0;
|
|
5825
|
+
if (latest && greater(latest, current)) log(`update: ${latest} available (running ${current})`);
|
|
5826
|
+
} catch (err) {
|
|
5827
|
+
error = err.message;
|
|
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;
|
|
5836
|
+
return state();
|
|
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
|
+
};
|
|
5869
|
+
check();
|
|
5870
|
+
const timer = setInterval(() => void check(), DAY);
|
|
5871
|
+
timer.unref?.();
|
|
5872
|
+
return {
|
|
5873
|
+
state: () => {
|
|
5874
|
+
if (!checkedAt || Date.now() - checkedAt > DAY) check();
|
|
5875
|
+
return state();
|
|
5876
|
+
},
|
|
5877
|
+
check,
|
|
5878
|
+
install,
|
|
5879
|
+
stop: () => clearInterval(timer)
|
|
5880
|
+
};
|
|
5881
|
+
}
|
|
5781
5882
|
// src/index.ts
|
|
5782
5883
|
/**
|
|
5783
5884
|
* dsh-vidi host half: live stream jobs, local/online speech providers,
|
|
@@ -6389,6 +6490,8 @@ function apply(ctx, config) {
|
|
|
6389
6490
|
}
|
|
6390
6491
|
return send(res, 200, job.summary());
|
|
6391
6492
|
}
|
|
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());
|
|
6392
6495
|
if (route === "devices") {
|
|
6393
6496
|
const devices = await listDevices();
|
|
6394
6497
|
log(`devices: ${devices.filter((d) => d.kind !== "mic").length} picture, ${devices.filter((d) => d.kind === "mic").length} microphone`);
|
|
@@ -6828,6 +6931,17 @@ function apply(ctx, config) {
|
|
|
6828
6931
|
path: "/live/media",
|
|
6829
6932
|
handler: media
|
|
6830
6933
|
}), "dsh-vidi: media route");
|
|
6934
|
+
let updates;
|
|
6935
|
+
ctx.effect(() => {
|
|
6936
|
+
updates = updateChecker(log, () => {
|
|
6937
|
+
try {
|
|
6938
|
+
return ctx.get?.("pluginManager");
|
|
6939
|
+
} catch {
|
|
6940
|
+
return;
|
|
6941
|
+
}
|
|
6942
|
+
});
|
|
6943
|
+
return () => updates.stop();
|
|
6944
|
+
}, "dsh-vidi: update check");
|
|
6831
6945
|
ctx.effect(() => startOverlay(config.overlayPort, () => [...jobs.values()].filter((j) => j.summary().status === "running").at(-1) ?? [...jobs.values()].at(-1), (fn) => {
|
|
6832
6946
|
bus.on("job", fn);
|
|
6833
6947
|
return () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-vidi",
|
|
3
|
-
"version": "0.
|
|
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",
|