dsh-vidi 0.7.8 → 0.7.9
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 +65 -4
- package/lib/index.mjs +65 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -34790,9 +34790,10 @@ 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);
|
|
34796
34797
|
const box = (0, react.useRef)(null);
|
|
34797
34798
|
const [draft, setDraft] = (0, react.useState)("");
|
|
34798
34799
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
@@ -34890,9 +34891,9 @@ function Settings(props) {
|
|
|
34890
34891
|
className: "dshl-pick",
|
|
34891
34892
|
ref: box,
|
|
34892
34893
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
34893
|
-
className: `dshl-ctl icon ${open ? "on" : ""}`,
|
|
34894
|
+
className: `dshl-ctl icon ${open ? "on" : ""} ${update?.newer ? "dot" : ""}`,
|
|
34894
34895
|
onClick: () => onOpen(!open),
|
|
34895
|
-
title: t("in.settings"),
|
|
34896
|
+
title: update?.newer ? t("upd.available").replace("{v}", update.latest ?? "") : t("in.settings"),
|
|
34896
34897
|
"aria-expanded": open,
|
|
34897
34898
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon.gear, {})
|
|
34898
34899
|
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -35120,6 +35121,37 @@ function Settings(props) {
|
|
|
35120
35121
|
}
|
|
35121
35122
|
]
|
|
35122
35123
|
})]
|
|
35124
|
+
}),
|
|
35125
|
+
update && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
35126
|
+
className: "srow col version",
|
|
35127
|
+
children: [
|
|
35128
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
35129
|
+
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", {
|
|
35131
|
+
className: "new",
|
|
35132
|
+
children: t("upd.available").replace("{v}", update.latest ?? "")
|
|
35133
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
35134
|
+
className: "dshl-link",
|
|
35135
|
+
disabled: checking,
|
|
35136
|
+
onClick: () => {
|
|
35137
|
+
setChecking(true);
|
|
35138
|
+
onCheckUpdate?.().finally(() => {
|
|
35139
|
+
setChecking(false);
|
|
35140
|
+
setChecked(true);
|
|
35141
|
+
});
|
|
35142
|
+
},
|
|
35143
|
+
children: checking ? t("upd.checking") : checked && !update.error ? t("upd.latest") : t("upd.check")
|
|
35144
|
+
})]
|
|
35145
|
+
}),
|
|
35146
|
+
update.newer && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
35147
|
+
className: "hint",
|
|
35148
|
+
children: t("upd.how")
|
|
35149
|
+
}),
|
|
35150
|
+
checked && update.error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
35151
|
+
className: "hint",
|
|
35152
|
+
children: t("upd.failed")
|
|
35153
|
+
})
|
|
35154
|
+
]
|
|
35123
35155
|
})
|
|
35124
35156
|
]
|
|
35125
35157
|
})]
|
|
@@ -35389,6 +35421,15 @@ function LiveView(props) {
|
|
|
35389
35421
|
const linesBox = (0, react.useRef)(null);
|
|
35390
35422
|
const fileInput = (0, react.useRef)(null);
|
|
35391
35423
|
const active = !!job && (job.status === "resolving" || job.status === "running" || job.status === "stopping");
|
|
35424
|
+
const [update, setUpdate] = (0, react.useState)();
|
|
35425
|
+
(0, react.useEffect)(() => {
|
|
35426
|
+
fetch("/live/api/version").then((r) => r.ok ? r.json() : void 0).then(setUpdate).catch(() => {});
|
|
35427
|
+
}, []);
|
|
35428
|
+
const checkUpdate = async () => {
|
|
35429
|
+
try {
|
|
35430
|
+
setUpdate(await post("version", {}));
|
|
35431
|
+
} catch {}
|
|
35432
|
+
};
|
|
35392
35433
|
const [srcTab, setSrcTabRaw] = (0, react.useState)("link");
|
|
35393
35434
|
const setSrcTab = (v) => {
|
|
35394
35435
|
setSrcTabRaw(v);
|
|
@@ -36230,6 +36271,8 @@ function LiveView(props) {
|
|
|
36230
36271
|
},
|
|
36231
36272
|
open: settingsOpen,
|
|
36232
36273
|
onOpen: setSettingsOpen,
|
|
36274
|
+
update,
|
|
36275
|
+
onCheckUpdate: checkUpdate,
|
|
36233
36276
|
t
|
|
36234
36277
|
})
|
|
36235
36278
|
] });
|
|
@@ -37178,6 +37221,13 @@ const en = {
|
|
|
37178
37221
|
"note.noModel": "No model set up, so subtitles stay in the original language.",
|
|
37179
37222
|
"note.install": "Install first:",
|
|
37180
37223
|
"push.title": "Stream here from OBS",
|
|
37224
|
+
"upd.version": "Vidi {v}",
|
|
37225
|
+
"upd.check": "Check for updates",
|
|
37226
|
+
"upd.checking": "Checking…",
|
|
37227
|
+
"upd.latest": "Up to date",
|
|
37228
|
+
"upd.available": "Version {v} is out",
|
|
37229
|
+
"upd.how": "Update it from DSH’s Plugins page, then restart the app.",
|
|
37230
|
+
"upd.failed": "Could not reach npm just now; it checks again tomorrow.",
|
|
37181
37231
|
"src.tip": "Where the video comes from",
|
|
37182
37232
|
"src.link": "Link",
|
|
37183
37233
|
"src.file": "Local file",
|
|
@@ -37596,6 +37646,13 @@ const zh = {
|
|
|
37596
37646
|
"note.noModel": "还没配置模型,字幕只显示原文",
|
|
37597
37647
|
"note.install": "需要先安装:",
|
|
37598
37648
|
"push.title": "用 OBS 推流到这里",
|
|
37649
|
+
"upd.version": "Vidi {v}",
|
|
37650
|
+
"upd.check": "检查更新",
|
|
37651
|
+
"upd.checking": "正在检查…",
|
|
37652
|
+
"upd.latest": "已是最新",
|
|
37653
|
+
"upd.available": "有新版本 {v}",
|
|
37654
|
+
"upd.how": "到 DSH 的「插件」页面更新,再重启 app。",
|
|
37655
|
+
"upd.failed": "这会儿连不上 npm,明天会再查一次。",
|
|
37599
37656
|
"src.tip": "视频从哪里来",
|
|
37600
37657
|
"src.link": "链接",
|
|
37601
37658
|
"src.file": "本地文件",
|
|
@@ -37989,6 +38046,8 @@ const CSS = `
|
|
|
37989
38046
|
background: var(--l1); color: var(--muted); font-size: 13px; cursor: pointer; }
|
|
37990
38047
|
.dshl-ctl.icon { width: 40px; padding: 0; }
|
|
37991
38048
|
.dshl-ctl.icon svg { width: 18px; height: 18px; }
|
|
38049
|
+
.dshl-ctl.icon.dot { position: relative; }
|
|
38050
|
+
.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
38051
|
.dshl-ctl:hover, .dshl-ctl.on { background: var(--hover); color: var(--ink); }
|
|
37993
38052
|
|
|
37994
38053
|
.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 +38526,8 @@ body > .dshl-menu { z-index: 2147483002; }
|
|
|
38467
38526
|
.dshl .srow .duo { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: 8px; }
|
|
38468
38527
|
.dshl .srow .duo > .dshl-select { width: 100%; }
|
|
38469
38528
|
.dshl-pop.settings .srow + .srow { border-top: 1px solid var(--line-soft); }
|
|
38529
|
+
.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
|
+
.dshl-pop.settings .srow.version .new { color: #e5484d; font-weight: 550; }
|
|
38470
38531
|
.dshl-pop.settings .srow > .dshl-select, .dshl-pop.settings .srow > .dshl-seg { width: 168px; }
|
|
38471
38532
|
.dshl-pop.settings .srow > .dshl-seg button { flex: 1; padding: 0 6px; }
|
|
38472
38533
|
.dshl .srow.col { display: grid; justify-content: stretch; gap: 8px; padding: 10px 0; }
|
package/lib/index.mjs
CHANGED
|
@@ -5778,6 +5778,65 @@ function metered(llm, meter) {
|
|
|
5778
5778
|
}
|
|
5779
5779
|
};
|
|
5780
5780
|
}
|
|
5781
|
+
// src/updates.ts
|
|
5782
|
+
const DAY = 864e5;
|
|
5783
|
+
/** a > b for plain x.y.z versions (pre-releases count as older than the release). */
|
|
5784
|
+
function greater(a, b) {
|
|
5785
|
+
const parse = (v) => {
|
|
5786
|
+
const [core = "", pre] = v.split("-");
|
|
5787
|
+
return {
|
|
5788
|
+
n: core.split(".").map((x) => Number(x) || 0),
|
|
5789
|
+
pre
|
|
5790
|
+
};
|
|
5791
|
+
};
|
|
5792
|
+
const x = parse(a), y = parse(b);
|
|
5793
|
+
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
|
+
return !x.pre && !!y.pre;
|
|
5795
|
+
}
|
|
5796
|
+
function updateChecker(log) {
|
|
5797
|
+
let current = "0.0.0";
|
|
5798
|
+
try {
|
|
5799
|
+
current = String(JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version);
|
|
5800
|
+
} catch {}
|
|
5801
|
+
let latest, checkedAt, error;
|
|
5802
|
+
let running;
|
|
5803
|
+
const state = () => ({
|
|
5804
|
+
current,
|
|
5805
|
+
latest,
|
|
5806
|
+
newer: !!latest && greater(latest, current),
|
|
5807
|
+
checkedAt,
|
|
5808
|
+
error
|
|
5809
|
+
});
|
|
5810
|
+
const check = () => running ??= (async () => {
|
|
5811
|
+
try {
|
|
5812
|
+
const r = await fetch("https://registry.npmjs.org/dsh-vidi/latest", {
|
|
5813
|
+
signal: AbortSignal.timeout(1e4),
|
|
5814
|
+
headers: { accept: "application/json" }
|
|
5815
|
+
});
|
|
5816
|
+
if (!r.ok) throw new Error(`registry ${r.status}`);
|
|
5817
|
+
latest = String((await r.json()).version ?? "") || void 0;
|
|
5818
|
+
error = void 0;
|
|
5819
|
+
if (latest && greater(latest, current)) log(`update: ${latest} available (running ${current})`);
|
|
5820
|
+
} catch (err) {
|
|
5821
|
+
error = err.message;
|
|
5822
|
+
} finally {
|
|
5823
|
+
checkedAt = Date.now();
|
|
5824
|
+
running = void 0;
|
|
5825
|
+
}
|
|
5826
|
+
return state();
|
|
5827
|
+
})();
|
|
5828
|
+
check();
|
|
5829
|
+
const timer = setInterval(() => void check(), DAY);
|
|
5830
|
+
timer.unref?.();
|
|
5831
|
+
return {
|
|
5832
|
+
state: () => {
|
|
5833
|
+
if (!checkedAt || Date.now() - checkedAt > DAY) check();
|
|
5834
|
+
return state();
|
|
5835
|
+
},
|
|
5836
|
+
check,
|
|
5837
|
+
stop: () => clearInterval(timer)
|
|
5838
|
+
};
|
|
5839
|
+
}
|
|
5781
5840
|
// src/index.ts
|
|
5782
5841
|
/**
|
|
5783
5842
|
* dsh-vidi host half: live stream jobs, local/online speech providers,
|
|
@@ -6389,6 +6448,7 @@ function apply(ctx, config) {
|
|
|
6389
6448
|
}
|
|
6390
6449
|
return send(res, 200, job.summary());
|
|
6391
6450
|
}
|
|
6451
|
+
if (route === "version") return send(res, 200, req.method === "POST" ? await updates.check() : updates.state());
|
|
6392
6452
|
if (route === "devices") {
|
|
6393
6453
|
const devices = await listDevices();
|
|
6394
6454
|
log(`devices: ${devices.filter((d) => d.kind !== "mic").length} picture, ${devices.filter((d) => d.kind === "mic").length} microphone`);
|
|
@@ -6828,6 +6888,11 @@ function apply(ctx, config) {
|
|
|
6828
6888
|
path: "/live/media",
|
|
6829
6889
|
handler: media
|
|
6830
6890
|
}), "dsh-vidi: media route");
|
|
6891
|
+
let updates;
|
|
6892
|
+
ctx.effect(() => {
|
|
6893
|
+
updates = updateChecker(log);
|
|
6894
|
+
return () => updates.stop();
|
|
6895
|
+
}, "dsh-vidi: update check");
|
|
6831
6896
|
ctx.effect(() => startOverlay(config.overlayPort, () => [...jobs.values()].filter((j) => j.summary().status === "running").at(-1) ?? [...jobs.values()].at(-1), (fn) => {
|
|
6832
6897
|
bus.on("job", fn);
|
|
6833
6898
|
return () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-vidi",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.9",
|
|
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",
|