dsh-vidi 0.8.8 → 0.9.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 +160 -56
- package/lib/index.mjs +5 -3
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -358,6 +358,17 @@ const Icon = {
|
|
|
358
358
|
rx: "2"
|
|
359
359
|
})
|
|
360
360
|
}),
|
|
361
|
+
timer: () => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
362
|
+
viewBox: "0 0 24 24",
|
|
363
|
+
width: "18",
|
|
364
|
+
height: "18",
|
|
365
|
+
...P,
|
|
366
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
367
|
+
cx: "12",
|
|
368
|
+
cy: "13.5",
|
|
369
|
+
r: "7.5"
|
|
370
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M12 9.5v4l2.5 1.5M10 3h4M12 3v3" })]
|
|
371
|
+
}),
|
|
361
372
|
live: () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
362
373
|
viewBox: "0 0 24 24",
|
|
363
374
|
width: "16",
|
|
@@ -1062,7 +1073,7 @@ const BGS = {
|
|
|
1062
1073
|
* position and background.
|
|
1063
1074
|
*/
|
|
1064
1075
|
function SubtitleMenu(props) {
|
|
1065
|
-
const { lines, onLines, options, site, name, style, onStyle, t } = props;
|
|
1076
|
+
const { lines, onLines, options, site, name, style, onStyle, spoken, t } = props;
|
|
1066
1077
|
const main = lines[0] ?? "src";
|
|
1067
1078
|
const second = lines[1] ?? "";
|
|
1068
1079
|
const label = (k) => site.find((s) => s.key === k)?.label ?? name(k);
|
|
@@ -1127,6 +1138,21 @@ function SubtitleMenu(props) {
|
|
|
1127
1138
|
className: "swap",
|
|
1128
1139
|
onClick: () => onLines([second, main]),
|
|
1129
1140
|
children: ["⇅ ", t("sub.swapMain")]
|
|
1141
|
+
}),
|
|
1142
|
+
spoken && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1143
|
+
className: "slot",
|
|
1144
|
+
title: t("set.spoken.tip"),
|
|
1145
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("set.spoken") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pick, {
|
|
1146
|
+
value: spoken.value,
|
|
1147
|
+
onChange: spoken.onChange,
|
|
1148
|
+
options: [{
|
|
1149
|
+
value: "auto",
|
|
1150
|
+
label: t("set.auto")
|
|
1151
|
+
}, ...spoken.options.map(([k, v]) => ({
|
|
1152
|
+
value: k,
|
|
1153
|
+
label: v
|
|
1154
|
+
}))]
|
|
1155
|
+
})]
|
|
1130
1156
|
})
|
|
1131
1157
|
]
|
|
1132
1158
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -34384,14 +34410,9 @@ const CLOCK$1 = (s) => {
|
|
|
34384
34410
|
return `${h ? `${h}:` : ""}${String(m).padStart(h ? 2 : 1, "0")}:${String(ss).padStart(2, "0")}`;
|
|
34385
34411
|
};
|
|
34386
34412
|
const host = (s) => s.replace(/^[a-z]+:\/\//i, "").split("/")[0] ?? s;
|
|
34387
|
-
/**
|
|
34388
|
-
* The player's restream menu: saved destinations (tick the ones to push to),
|
|
34389
|
-
* adding one (platform, server address, stream key — copied from the
|
|
34390
|
-
* platform's own streaming tool), subtitles drawn in or not, picture size,
|
|
34391
|
-
* then start. While running, each destination shows its own state.
|
|
34392
|
-
*/
|
|
34393
34413
|
function RestreamPanel(props) {
|
|
34394
|
-
const { jobId, status, now, style, t } = props;
|
|
34414
|
+
const { jobId, status, now, style, timing, t } = props;
|
|
34415
|
+
const fromNow = () => timing ? timing.fromFor(timing.mode) : now;
|
|
34395
34416
|
const running = !!status?.running;
|
|
34396
34417
|
const [targets, setTargets] = (0, react.useState)([]);
|
|
34397
34418
|
const [picked, setPicked] = (0, react.useState)(() => {
|
|
@@ -34463,7 +34484,7 @@ function RestreamPanel(props) {
|
|
|
34463
34484
|
jobId,
|
|
34464
34485
|
action: "start",
|
|
34465
34486
|
targets: picked.filter((id) => targets.some((x) => x.id === id)),
|
|
34466
|
-
from:
|
|
34487
|
+
from: fromNow(),
|
|
34467
34488
|
burn,
|
|
34468
34489
|
height,
|
|
34469
34490
|
style
|
|
@@ -34491,12 +34512,39 @@ function RestreamPanel(props) {
|
|
|
34491
34512
|
jobId,
|
|
34492
34513
|
action: "start",
|
|
34493
34514
|
targets: [id],
|
|
34494
|
-
from:
|
|
34515
|
+
from: fromNow(),
|
|
34495
34516
|
burn,
|
|
34496
34517
|
height,
|
|
34497
34518
|
style
|
|
34498
34519
|
}).catch((e) => setError(e.message));
|
|
34499
34520
|
};
|
|
34521
|
+
const switchMode = async (m) => {
|
|
34522
|
+
if (!timing || m === timing.mode) return;
|
|
34523
|
+
timing.onMode(m);
|
|
34524
|
+
if (!running) return;
|
|
34525
|
+
const ids = status.targets.map((x) => x.id);
|
|
34526
|
+
setBusy(true);
|
|
34527
|
+
setError("");
|
|
34528
|
+
try {
|
|
34529
|
+
await post$2("restream", {
|
|
34530
|
+
jobId,
|
|
34531
|
+
action: "stop"
|
|
34532
|
+
});
|
|
34533
|
+
await post$2("restream", {
|
|
34534
|
+
jobId,
|
|
34535
|
+
action: "start",
|
|
34536
|
+
targets: ids,
|
|
34537
|
+
from: timing.fromFor(m),
|
|
34538
|
+
burn,
|
|
34539
|
+
height,
|
|
34540
|
+
style
|
|
34541
|
+
});
|
|
34542
|
+
} catch (e) {
|
|
34543
|
+
setError(e.message);
|
|
34544
|
+
} finally {
|
|
34545
|
+
setBusy(false);
|
|
34546
|
+
}
|
|
34547
|
+
};
|
|
34500
34548
|
const stateOf = (id) => running ? status.targets.find((x) => x.id === id) : void 0;
|
|
34501
34549
|
const chosen = picked.filter((id) => targets.some((x) => x.id === id));
|
|
34502
34550
|
if (editing) {
|
|
@@ -34678,6 +34726,32 @@ function RestreamPanel(props) {
|
|
|
34678
34726
|
className: "rs-err",
|
|
34679
34727
|
children: status.targets.filter((x) => x.message && x.state !== "live").map((x) => `${pname(x.platform)}:${x.message}`).join(";")
|
|
34680
34728
|
}),
|
|
34729
|
+
timing && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
34730
|
+
className: "rs-mode",
|
|
34731
|
+
children: [
|
|
34732
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
34733
|
+
className: "rs-sub",
|
|
34734
|
+
children: t("rs.mode")
|
|
34735
|
+
}),
|
|
34736
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
34737
|
+
className: "seg",
|
|
34738
|
+
children: [
|
|
34739
|
+
"live",
|
|
34740
|
+
"realtime",
|
|
34741
|
+
"polished"
|
|
34742
|
+
].map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
34743
|
+
className: timing.mode === m ? "on" : "",
|
|
34744
|
+
disabled: busy,
|
|
34745
|
+
onClick: () => void switchMode(m),
|
|
34746
|
+
children: t(`mode.${m}`)
|
|
34747
|
+
}, m))
|
|
34748
|
+
}),
|
|
34749
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
34750
|
+
className: "rs-hint",
|
|
34751
|
+
children: t(`rs.mode.${timing.mode}`).replace("{s}", String(Math.max(1, Math.round(timing.behindFor(timing.mode)))))
|
|
34752
|
+
})
|
|
34753
|
+
]
|
|
34754
|
+
}),
|
|
34681
34755
|
!running && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
34682
34756
|
className: "rs-opts",
|
|
34683
34757
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -34849,7 +34923,7 @@ async function post$1(path, body) {
|
|
|
34849
34923
|
return j;
|
|
34850
34924
|
}
|
|
34851
34925
|
function Settings(props) {
|
|
34852
|
-
const { engine, onEngine,
|
|
34926
|
+
const { engine, onEngine, login, onLogin, browsers, providers, shared, name, onKey, disabled, open, onOpen, update, onCheckUpdate, t } = props;
|
|
34853
34927
|
const [checking, setChecking] = (0, react.useState)(false);
|
|
34854
34928
|
const [checked, setChecked] = (0, react.useState)(false);
|
|
34855
34929
|
const [installing, setInstalling] = (0, react.useState)(false);
|
|
@@ -35161,43 +35235,6 @@ function Settings(props) {
|
|
|
35161
35235
|
})
|
|
35162
35236
|
]
|
|
35163
35237
|
}),
|
|
35164
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
35165
|
-
className: "srow col",
|
|
35166
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
35167
|
-
className: "pair",
|
|
35168
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("set.mode") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
35169
|
-
className: "dshl-seg",
|
|
35170
|
-
children: [
|
|
35171
|
-
"live",
|
|
35172
|
-
"realtime",
|
|
35173
|
-
"polished"
|
|
35174
|
-
].map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
35175
|
-
className: mode === m ? "on" : "",
|
|
35176
|
-
title: t(`mode.${m}.tip`),
|
|
35177
|
-
onClick: () => onMode(m),
|
|
35178
|
-
children: t(`mode.${m}`)
|
|
35179
|
-
}, m))
|
|
35180
|
-
})]
|
|
35181
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
35182
|
-
className: "hint",
|
|
35183
|
-
children: t(`mode.${mode}.tip`)
|
|
35184
|
-
})]
|
|
35185
|
-
}),
|
|
35186
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
35187
|
-
className: "srow",
|
|
35188
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("set.spoken") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pick, {
|
|
35189
|
-
value: spoken,
|
|
35190
|
-
disabled,
|
|
35191
|
-
onChange: onSpoken,
|
|
35192
|
-
options: [{
|
|
35193
|
-
value: "auto",
|
|
35194
|
-
label: t("set.auto")
|
|
35195
|
-
}, ...langOptions.map(([k, v]) => ({
|
|
35196
|
-
value: k,
|
|
35197
|
-
label: v
|
|
35198
|
-
}))]
|
|
35199
|
-
})]
|
|
35200
|
-
}),
|
|
35201
35238
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
35202
35239
|
className: "srow",
|
|
35203
35240
|
title: t("set.login.tip"),
|
|
@@ -36014,6 +36051,18 @@ function LiveView(props) {
|
|
|
36014
36051
|
const missing = deps.filter((d) => !d.ok && (d.name === "ffmpeg" || d.name === "yt-dlp" || (engine || "local") === "local" && d.name.startsWith("whisper")));
|
|
36015
36052
|
const needsModel = !hasTranslator && shownLines.some((l) => l !== "src");
|
|
36016
36053
|
const hasMain = !!job && !(job.status === "error" && !job.files.some((f) => /\.(mp4|m4a|srt|vtt)$/.test(f)));
|
|
36054
|
+
const liveEdge = job?.recorded ?? now;
|
|
36055
|
+
const pushFrom = (m) => {
|
|
36056
|
+
const firstPass = subs.ready ?? subs.at;
|
|
36057
|
+
const at = m === "live" ? liveEdge - 2 : m === "realtime" ? firstPass : Math.max(lastPolished, firstPass - 150);
|
|
36058
|
+
return Math.max(0, Math.min(at, liveEdge));
|
|
36059
|
+
};
|
|
36060
|
+
const pushTiming = job && !job.vod && job.status === "running" ? {
|
|
36061
|
+
mode,
|
|
36062
|
+
onMode: changeMode,
|
|
36063
|
+
fromFor: pushFrom,
|
|
36064
|
+
behindFor: (m) => liveEdge - pushFrom(m)
|
|
36065
|
+
} : void 0;
|
|
36017
36066
|
(0, react.useEffect)(() => {
|
|
36018
36067
|
if (job && !hasMain) setSrcTabRaw(job.source === "device" ? "camera" : job.source === "push" ? "push" : job.source === "file" ? "file" : "link");
|
|
36019
36068
|
}, [job?.id, hasMain]);
|
|
@@ -36388,11 +36437,6 @@ function LiveView(props) {
|
|
|
36388
36437
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Settings, {
|
|
36389
36438
|
engine: engine || "local",
|
|
36390
36439
|
onEngine: setEngine,
|
|
36391
|
-
mode,
|
|
36392
|
-
onMode: changeMode,
|
|
36393
|
-
spoken,
|
|
36394
|
-
onSpoken: setSpoken,
|
|
36395
|
-
langOptions,
|
|
36396
36440
|
login,
|
|
36397
36441
|
onLogin: chooseLogin,
|
|
36398
36442
|
browsers,
|
|
@@ -36580,9 +36624,38 @@ function LiveView(props) {
|
|
|
36580
36624
|
name: nameWithSpoken,
|
|
36581
36625
|
style: subStyle,
|
|
36582
36626
|
onStyle: setSubStyle,
|
|
36627
|
+
spoken: {
|
|
36628
|
+
value: spoken,
|
|
36629
|
+
options: langOptions,
|
|
36630
|
+
onChange: setSpoken
|
|
36631
|
+
},
|
|
36583
36632
|
t
|
|
36584
36633
|
}) })
|
|
36585
36634
|
},
|
|
36635
|
+
...!job.vod && job.status === "running" ? [{
|
|
36636
|
+
id: "mode",
|
|
36637
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon.timer, {}),
|
|
36638
|
+
title: t("set.mode"),
|
|
36639
|
+
label: t(`mode.${mode}`),
|
|
36640
|
+
content: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
36641
|
+
className: "dshl-modemenu",
|
|
36642
|
+
children: [
|
|
36643
|
+
"live",
|
|
36644
|
+
"realtime",
|
|
36645
|
+
"polished"
|
|
36646
|
+
].map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
36647
|
+
className: `mm ${mode === m ? "on" : ""}`,
|
|
36648
|
+
onClick: () => changeMode(m),
|
|
36649
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
36650
|
+
className: "n",
|
|
36651
|
+
children: [t(`mode.${m}`), mode === m && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon.check, {})]
|
|
36652
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
36653
|
+
className: "d",
|
|
36654
|
+
children: t(`mode.${m}.tip`)
|
|
36655
|
+
})]
|
|
36656
|
+
}, m))
|
|
36657
|
+
})
|
|
36658
|
+
}] : [],
|
|
36586
36659
|
{
|
|
36587
36660
|
id: "restream",
|
|
36588
36661
|
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon.push, {}),
|
|
@@ -36594,6 +36667,7 @@ function LiveView(props) {
|
|
|
36594
36667
|
status: job.restream,
|
|
36595
36668
|
now,
|
|
36596
36669
|
style: subStyle,
|
|
36670
|
+
timing: pushTiming,
|
|
36597
36671
|
t
|
|
36598
36672
|
})
|
|
36599
36673
|
},
|
|
@@ -37418,6 +37492,11 @@ const en = {
|
|
|
37418
37492
|
"dev.blocked": "No picture or sound from the device: DeepSeek Harness needs the system’s permission. Open System Settings, switch DeepSeek Harness on, then retry.",
|
|
37419
37493
|
"dev.denied": "DeepSeek Harness needs permission to use the {d}. Open System Settings, switch it on in the list, then retry.",
|
|
37420
37494
|
"dev.and": " and ",
|
|
37495
|
+
"set.spoken.tip": "The language people speak in this video; Auto detects it.",
|
|
37496
|
+
"rs.mode": "Subtitle mode of the push-out",
|
|
37497
|
+
"rs.mode.live": "Pushed out about {s} s behind; subtitles come a little after the words.",
|
|
37498
|
+
"rs.mode.realtime": "Pushed out about {s} s behind, with first-pass subtitles in step.",
|
|
37499
|
+
"rs.mode.polished": "Pushed out about {s} s behind, with polished subtitles.",
|
|
37421
37500
|
"own.live": "Live",
|
|
37422
37501
|
"own.delayed": "As pushed out",
|
|
37423
37502
|
"own.toLive": "Show the live picture large",
|
|
@@ -37862,6 +37941,11 @@ const zh = {
|
|
|
37862
37941
|
"dev.blocked": "设备没有传来画面和声音:DeepSeek Harness 需要系统授权。点「打开系统设置」,在列表里打开 DeepSeek Harness,再点重试。",
|
|
37863
37942
|
"dev.denied": "DeepSeek Harness 需要{d}权限。点「打开系统设置」,在列表里打开它,再点重试。",
|
|
37864
37943
|
"dev.and": "和",
|
|
37944
|
+
"set.spoken.tip": "视频里说的是哪种语言;自动 = 自己识别。",
|
|
37945
|
+
"rs.mode": "推流用的字幕模式",
|
|
37946
|
+
"rs.mode.live": "推出去比实时晚约 {s} 秒,字幕会比说话稍晚出现。",
|
|
37947
|
+
"rs.mode.realtime": "推出去比实时晚约 {s} 秒,带对齐好的初版字幕。",
|
|
37948
|
+
"rs.mode.polished": "推出去比实时晚约 {s} 秒,带精修字幕。",
|
|
37865
37949
|
"own.live": "实时画面",
|
|
37866
37950
|
"own.delayed": "推流画面",
|
|
37867
37951
|
"own.toLive": "放大实时画面",
|
|
@@ -38402,6 +38486,9 @@ html[data-platform='darwin'] .dshl.page .dshl-top :is(button, input, label, a, .
|
|
|
38402
38486
|
outline: 1px solid rgba(255,255,255,.28); box-shadow: 0 6px 24px rgba(0,0,0,.5); cursor: pointer; transition: bottom .25s; }
|
|
38403
38487
|
.dshl-stage.idle .dshl-vbox.pip, .dshl-stage.idle .dshl-livecam.pip { bottom: 14px; }
|
|
38404
38488
|
.dshl-stage .pip .dshl-sub { transform: translateX(-50%) !important; }
|
|
38489
|
+
.dshl-rs .rs-mode { display: grid; gap: 6px; margin: 10px 0 4px; }
|
|
38490
|
+
.dshl-rs .rs-mode .seg { display: flex; }
|
|
38491
|
+
.dshl-rs .rs-mode .seg button { flex: 1; }
|
|
38405
38492
|
.dshl-piplabel { position: absolute; top: 6px; left: 6px; z-index: 3; padding: 2px 7px; border-radius: 5px; background: rgba(0,0,0,.6); color: #fff; font-size: 11px; pointer-events: none; }
|
|
38406
38493
|
.dshl-stage.idle { cursor: none; }
|
|
38407
38494
|
.dshl-holdnote { position: absolute; top: 14px; left: 50%; z-index: 4; display: flex; align-items: center; gap: 8px; padding: 6px 12px; border-radius: 999px; transform: translateX(-50%);
|
|
@@ -38526,6 +38613,13 @@ html[data-platform='darwin'] .dshl.page .dshl-top :is(button, input, label, a, .
|
|
|
38526
38613
|
.dshl-menu .dshl-seg button.on { background: rgba(255,255,255,.92); color: #111; box-shadow: none; }
|
|
38527
38614
|
.dshl-menu .dshl-switch { background: rgba(255,255,255,.22); }
|
|
38528
38615
|
.dshl-menu .dshl-switch.on { background: var(--accent); }
|
|
38616
|
+
.dshl-modemenu { display: grid; gap: 4px; width: 300px; max-width: 100%; }
|
|
38617
|
+
.dshl-modemenu .mm { display: grid; gap: 3px; padding: 9px 10px; border: 0; border-radius: 8px; background: none; color: inherit; text-align: left; cursor: pointer; }
|
|
38618
|
+
.dshl-modemenu .mm:hover { background: rgba(255,255,255,.08); }
|
|
38619
|
+
.dshl-modemenu .mm.on { background: rgba(255,255,255,.12); }
|
|
38620
|
+
.dshl-modemenu .n { display: flex; align-items: center; justify-content: space-between; font-size: 13.5px; font-weight: 600; }
|
|
38621
|
+
.dshl-modemenu .n svg { width: 14px; height: 14px; }
|
|
38622
|
+
.dshl-modemenu .d { color: rgba(255,255,255,.62); font-size: 12px; line-height: 1.45; }
|
|
38529
38623
|
.dshl-menu .opt { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 32px; padding: 0 6px; color: var(--muted); }
|
|
38530
38624
|
.dshl-menu .opt .dshl-seg { max-width: 100%; overflow-x: auto; scrollbar-width: none; }
|
|
38531
38625
|
.dshl-menu .opt input[type=range] { flex: 1; max-width: 180px; accent-color: var(--accent); }
|
|
@@ -38893,8 +38987,14 @@ async function openPage(sessions, opts = {}) {
|
|
|
38893
38987
|
}
|
|
38894
38988
|
async function showPage(sessions, opts) {
|
|
38895
38989
|
const current = sessions.current();
|
|
38896
|
-
const
|
|
38897
|
-
|
|
38990
|
+
const fresh = () => pageSession(sessions, opts.workspaces, opts.title ?? "Video");
|
|
38991
|
+
let sid = opts.sessionId && sessions.has(opts.sessionId) ? opts.sessionId : await fresh();
|
|
38992
|
+
if (sid !== current) try {
|
|
38993
|
+
sessions.open(sid);
|
|
38994
|
+
} catch {
|
|
38995
|
+
sid = await fresh();
|
|
38996
|
+
sessions.open(sid);
|
|
38997
|
+
}
|
|
38898
38998
|
if (panelHost) {
|
|
38899
38999
|
pageStore.set({
|
|
38900
39000
|
open: true,
|
|
@@ -39037,7 +39137,11 @@ function SidebarButton(props) {
|
|
|
39037
39137
|
const pct = item?.subs === "running" && item.duration ? Math.min(99, Math.round(item.at / item.duration * 100)) : void 0;
|
|
39038
39138
|
const meta = !busy ? "" : item?.subs === "running" ? pct !== void 0 ? t("side.subs").replace("{p}", String(pct)) : t("side.subsLive") : item?.recording ? t("side.recording") : item?.loading ? t("side.loading") : t("side.downloading");
|
|
39039
39139
|
const thumb = busy && frame && (!item || frame.jobId === item.jobId) ? frame.dataUrl : void 0;
|
|
39040
|
-
const open = () => void openPage(sessions, item ? {
|
|
39140
|
+
const open = () => void openPage(sessions, item ? {
|
|
39141
|
+
sessionId: item.conversationId,
|
|
39142
|
+
workspaces,
|
|
39143
|
+
title: t("view.live")
|
|
39144
|
+
} : {
|
|
39041
39145
|
workspaces,
|
|
39042
39146
|
title: t("view.live")
|
|
39043
39147
|
});
|
package/lib/index.mjs
CHANGED
|
@@ -1912,8 +1912,6 @@ function deviceInput(c, q) {
|
|
|
1912
1912
|
if (process.platform === "darwin") return {
|
|
1913
1913
|
args: [
|
|
1914
1914
|
...q,
|
|
1915
|
-
"-use_wallclock_as_timestamps",
|
|
1916
|
-
"1",
|
|
1917
1915
|
"-f",
|
|
1918
1916
|
"avfoundation",
|
|
1919
1917
|
"-framerate",
|
|
@@ -1998,6 +1996,8 @@ var LiveJob = class LiveJob extends EventEmitter {
|
|
|
1998
1996
|
/** Real-time picture (own sources): the newest JPEG frame, and whether frames are coming. */
|
|
1999
1997
|
lastFrame;
|
|
2000
1998
|
previewOn = false;
|
|
1999
|
+
/** Closed by the user: no longer offered anywhere (its files stay). */
|
|
2000
|
+
closed = false;
|
|
2001
2001
|
id;
|
|
2002
2002
|
status = "resolving";
|
|
2003
2003
|
message;
|
|
@@ -2451,6 +2451,7 @@ var LiveJob = class LiveJob extends EventEmitter {
|
|
|
2451
2451
|
...picture,
|
|
2452
2452
|
"-map",
|
|
2453
2453
|
input.audio,
|
|
2454
|
+
...input.fps ? ["-af", "aresample=async=1:min_hard_comp=0.1:first_pts=0"] : [],
|
|
2454
2455
|
"-c:a",
|
|
2455
2456
|
"aac",
|
|
2456
2457
|
"-b:a",
|
|
@@ -6558,6 +6559,7 @@ function apply(ctx, config) {
|
|
|
6558
6559
|
const job = jobs.get(String(b.jobId));
|
|
6559
6560
|
if (!job) return send(res, 404, { error: "no such job" });
|
|
6560
6561
|
await job.close("closed");
|
|
6562
|
+
job.closed = true;
|
|
6561
6563
|
const conv = job.summary().conversationId;
|
|
6562
6564
|
if (byConversation.get(conv) === job.id) byConversation.set(conv, "");
|
|
6563
6565
|
try {
|
|
@@ -6601,7 +6603,7 @@ function apply(ctx, config) {
|
|
|
6601
6603
|
return send(res, 200, job.summary());
|
|
6602
6604
|
}
|
|
6603
6605
|
if (route === "activity") return send(res, 200, {
|
|
6604
|
-
items: [...jobs.values()].map((j) => j.summary()).filter((s) => s.status === "running" && !s.message || s.status === "resolving" || s.subs?.state === "running").map((s) => ({
|
|
6606
|
+
items: [...jobs.values()].filter((j) => !j.closed).map((j) => j.summary()).filter((s) => s.status === "running" && !s.message || s.status === "resolving" || s.subs?.state === "running").map((s) => ({
|
|
6605
6607
|
jobId: s.id,
|
|
6606
6608
|
conversationId: s.conversationId,
|
|
6607
6609
|
title: s.title,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-vidi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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",
|