dsh-vidi 0.9.4 → 0.9.5
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 +20 -4
- package/lib/index.mjs +49 -3
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -35466,7 +35466,7 @@ function History({ t, ui, onOpen }) {
|
|
|
35466
35466
|
onKeyDown: (e) => {
|
|
35467
35467
|
if (e.key === "Enter") onOpen(v);
|
|
35468
35468
|
},
|
|
35469
|
-
title: v.live && v.source === "url" && !v.running ? t("hist.goLive") : void 0,
|
|
35469
|
+
title: v.live && v.source === "url" && !v.running && !v.work ? t("hist.goLive") : void 0,
|
|
35470
35470
|
children: [
|
|
35471
35471
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
35472
35472
|
className: "th",
|
|
@@ -36293,7 +36293,7 @@ function LiveView(props) {
|
|
|
36293
36293
|
};
|
|
36294
36294
|
const openPast = async (v, replay = false) => {
|
|
36295
36295
|
setError("");
|
|
36296
|
-
if (!replay && v.live && v.source === "url" && v.url && !v.running) {
|
|
36296
|
+
if (!replay && v.live && v.source === "url" && v.url && !v.running && !v.work) {
|
|
36297
36297
|
if (v.conversationId !== sessionId && props.onOpenVideo && await props.onOpenVideo(v.conversationId, v.id, v.url)) return;
|
|
36298
36298
|
start(v.url, "url");
|
|
36299
36299
|
return;
|
|
@@ -37099,6 +37099,10 @@ function SubsButton(props) {
|
|
|
37099
37099
|
style: { ["--p"]: `${pct ?? 0}%` },
|
|
37100
37100
|
children: [
|
|
37101
37101
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("i", { className: "dot" }),
|
|
37102
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37103
|
+
className: "pz",
|
|
37104
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon.pause, {})
|
|
37105
|
+
}),
|
|
37102
37106
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37103
37107
|
className: "now",
|
|
37104
37108
|
children: pct !== void 0 ? t("subs.progress").replace("{p}", String(pct)) : t("subs.progressLive").replace("{t}", CLOCK(at))
|
|
@@ -37117,7 +37121,14 @@ function SubsButton(props) {
|
|
|
37117
37121
|
className: "dshl-subsbtn",
|
|
37118
37122
|
onClick: onResume,
|
|
37119
37123
|
title: t("subs.resume.tip").replace("{t}", CLOCK(at)),
|
|
37120
|
-
children: [
|
|
37124
|
+
children: [
|
|
37125
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37126
|
+
className: "pz on",
|
|
37127
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon.play, {})
|
|
37128
|
+
}),
|
|
37129
|
+
t("subs.resume"),
|
|
37130
|
+
pct !== void 0 ? ` · ${pct}%` : ""
|
|
37131
|
+
]
|
|
37121
37132
|
});
|
|
37122
37133
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
37123
37134
|
className: "dshl-subsbtn",
|
|
@@ -38918,7 +38929,12 @@ html[data-platform='darwin'] .dshl.page .dshl-top :is(button, input, label, a, .
|
|
|
38918
38929
|
@container (max-width: 640px) { .dshl-subsbtn .now { display: none; } .dshl-subsbtn.running:not(:hover) .short { display: inline; } }
|
|
38919
38930
|
.dshl-subsbtn.running:hover .now { display: none; }
|
|
38920
38931
|
.dshl-subsbtn.running:hover .act { display: inline; }
|
|
38921
|
-
.dshl-subsbtn
|
|
38932
|
+
.dshl-subsbtn .pz { display: none; margin: 0 -2px 0 -4px; }
|
|
38933
|
+
.dshl-subsbtn .pz svg { display: block; width: 15px; height: 15px; }
|
|
38934
|
+
.dshl-subsbtn .pz.on { display: inline-flex; }
|
|
38935
|
+
/* Hover on a running one: the pause sign stands where the pulsing dot was. */
|
|
38936
|
+
.dshl-subsbtn.running:hover .dot { display: none; }
|
|
38937
|
+
.dshl-subsbtn.running:hover .pz { display: inline-flex; }
|
|
38922
38938
|
@container (max-width: 520px) { .dshl-subsbtn { margin: 0 2px; padding: 0 9px; } }
|
|
38923
38939
|
.dshl-starter { position: relative; display: inline-flex; }
|
|
38924
38940
|
.dshl-startpop { position: absolute; left: 50%; bottom: calc(100% + 26px); z-index: 6; display: grid; gap: 10px; width: 290px; padding: 12px 12px 14px; transform: translateX(-50%);
|
package/lib/index.mjs
CHANGED
|
@@ -2021,6 +2021,22 @@ function cutNear(cs, ratio) {
|
|
|
2021
2021
|
}
|
|
2022
2022
|
return best > 0 ? best : Math.max(1, Math.min(n - 1, target));
|
|
2023
2023
|
}
|
|
2024
|
+
/**
|
|
2025
|
+
* A line meant to be in `lang` that is written in another script: live interpretation now and then
|
|
2026
|
+
* passes the speaker's words through untranslated (Chinese in a Japanese line). Latin words (names,
|
|
2027
|
+
* brands) never count; a Japanese line has kana, a Chinese one none, a Korean one hangul.
|
|
2028
|
+
*/
|
|
2029
|
+
function wrongScript(text, lang) {
|
|
2030
|
+
const n = (re) => (text.match(re) ?? []).length;
|
|
2031
|
+
const han = n(/[\u3400-\u9fff]/g), kana = n(/[\u3040-\u30ff]/g), hangul = n(/[\uac00-\ud7af\u1100-\u11ff]/g);
|
|
2032
|
+
const letters = n(/\p{L}/gu);
|
|
2033
|
+
const base = lang.split("-")[0];
|
|
2034
|
+
if (base === "ja") return kana === 0 && (han >= 4 || /[是吧嗯么们这那的呢吗啊呃对没还就说几]/.test(text)) || hangul >= 2;
|
|
2035
|
+
if (base === "zh") return kana >= 2 || hangul >= 2;
|
|
2036
|
+
if (base === "ko") return hangul === 0 && han + kana >= 3;
|
|
2037
|
+
const cjk = han + kana + hangul;
|
|
2038
|
+
return cjk >= 3 && cjk > letters * .3;
|
|
2039
|
+
}
|
|
2024
2040
|
/** When a video was first opened: its folder is named after that moment (UTC); older saves could carry a later time. */
|
|
2025
2041
|
function openedAt(id, saved) {
|
|
2026
2042
|
const named = /^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})/.exec(id);
|
|
@@ -2221,6 +2237,7 @@ var LiveJob = class LiveJob extends EventEmitter {
|
|
|
2221
2237
|
state: j.subs?.state === "done" ? "done" : at > 0 ? "paused" : "off",
|
|
2222
2238
|
at
|
|
2223
2239
|
};
|
|
2240
|
+
setTimeout(() => job.repairEchoes(), 3e3);
|
|
2224
2241
|
if (!existsSync(join(dir, "recording.mp4"))) job.remux();
|
|
2225
2242
|
return job;
|
|
2226
2243
|
} catch {
|
|
@@ -2857,20 +2874,49 @@ var LiveJob = class LiveJob extends EventEmitter {
|
|
|
2857
2874
|
this.emit("cue", cue);
|
|
2858
2875
|
if (cue.final) {
|
|
2859
2876
|
this.deps.glossary.notice(cue.src);
|
|
2860
|
-
|
|
2877
|
+
const echoed = this.echoOf(cue);
|
|
2878
|
+
if (echoed) this.translate(cue, echoed);
|
|
2879
|
+
else if (this.opts.mode !== "polished" && !this.provider?.translates && cue.tr === void 0 && this.targets().length) this.translate(cue);
|
|
2861
2880
|
else {
|
|
2862
2881
|
this.record(cue);
|
|
2863
2882
|
this.polisher.add(cue);
|
|
2864
2883
|
}
|
|
2865
2884
|
}
|
|
2866
2885
|
}
|
|
2867
|
-
|
|
2886
|
+
/**
|
|
2887
|
+
* Translations of a line that are in the wrong language: taken out (the line shows without them
|
|
2888
|
+
* until the proper one comes), and the text to translate from returned (the line's source, or the
|
|
2889
|
+
* echoed text itself when the line has none of its own: its source sits with the next line).
|
|
2890
|
+
*/
|
|
2891
|
+
echoOf(cue) {
|
|
2892
|
+
let from;
|
|
2893
|
+
for (const t of this.targets()) {
|
|
2894
|
+
const x = cue.tr?.[t];
|
|
2895
|
+
if (!x || !wrongScript(x, t)) continue;
|
|
2896
|
+
from ??= cue.src.trim() || x;
|
|
2897
|
+
delete cue.tr[t];
|
|
2898
|
+
}
|
|
2899
|
+
if (from && cue.tr && !Object.keys(cue.tr).length) cue.tr = void 0;
|
|
2900
|
+
return from;
|
|
2901
|
+
}
|
|
2902
|
+
/** Lines saved with a translation in the wrong language (before this check existed): translate them again. */
|
|
2903
|
+
repairEchoes() {
|
|
2904
|
+
for (const cue of this.cues) {
|
|
2905
|
+
if (!cue.final || cue.edited) continue;
|
|
2906
|
+
const from = this.echoOf(cue);
|
|
2907
|
+
if (from) {
|
|
2908
|
+
this.emit("cue", cue);
|
|
2909
|
+
this.translate(cue, from);
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
translate(cue, text = cue.src) {
|
|
2868
2914
|
const context = this.cues.filter((c) => c.final && c.id < cue.id).slice(-6);
|
|
2869
2915
|
this.pendingTranslations++;
|
|
2870
2916
|
this.translating = this.translating.then(async () => {
|
|
2871
2917
|
try {
|
|
2872
2918
|
const ref = this.siteText(cue.start, cue.end).map((x) => `[${x.lang}${x.auto ? ", auto" : ""}] ${x.text}`).join("\n");
|
|
2873
|
-
const tr = await this.deps.translator.translate(this.targets(),
|
|
2919
|
+
const tr = await this.deps.translator.translate(this.targets(), text, context, this.deps.glossary.forPrompt(), void 0, ref);
|
|
2874
2920
|
if (tr) {
|
|
2875
2921
|
cue.tr = {
|
|
2876
2922
|
...cue.tr,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-vidi",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.5",
|
|
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",
|