@mebius-io/web 0.5.4 → 0.6.1
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/dist/index.cjs +67 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.global.js +67 -9
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +67 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -810,6 +810,7 @@ function normalize(c, fallback) {
|
|
|
810
810
|
var TICK_MS = 100;
|
|
811
811
|
var STALE_MS = 5e3;
|
|
812
812
|
var MAX_QUEUE_MS = 1500;
|
|
813
|
+
var HIDDEN_GRACE_MS = 6e4;
|
|
813
814
|
var MebiusCaptions = class extends TypedEmitter {
|
|
814
815
|
/** @internal */
|
|
815
816
|
constructor(signaling, player, opts) {
|
|
@@ -820,26 +821,81 @@ var MebiusCaptions = class extends TypedEmitter {
|
|
|
820
821
|
this.es = null;
|
|
821
822
|
this.timer = null;
|
|
822
823
|
this.pending = /* @__PURE__ */ new Map();
|
|
823
|
-
|
|
824
|
+
/**
|
|
825
|
+
* segmentId -> the rev already handed to listeners. Not a Set: with interim
|
|
826
|
+
* revisions on, a segment stays pending while it is being corrected, and a
|
|
827
|
+
* plain "have I shown this id" check re-emits the same unchanged text on
|
|
828
|
+
* every 100ms tick. Comparing revs emits exactly once per actual revision.
|
|
829
|
+
*/
|
|
830
|
+
this.shown = /* @__PURE__ */ new Map();
|
|
831
|
+
/** Kept so the feed can be reopened after a hidden-tab suspend. */
|
|
832
|
+
this.streamId = null;
|
|
833
|
+
this.hiddenTimer = null;
|
|
834
|
+
this.onVisibility = null;
|
|
824
835
|
}
|
|
825
836
|
/** Open the SSE connection and begin emitting segments for `streamId`. */
|
|
826
837
|
start(streamId) {
|
|
827
838
|
if (this.es) return;
|
|
828
|
-
|
|
829
|
-
|
|
839
|
+
this.streamId = streamId;
|
|
840
|
+
this.openFeed();
|
|
841
|
+
this.watchVisibility();
|
|
842
|
+
}
|
|
843
|
+
/** Close the connection and drop all buffered segments. */
|
|
844
|
+
stop() {
|
|
845
|
+
this.streamId = null;
|
|
846
|
+
if (this.onVisibility && typeof document !== "undefined") {
|
|
847
|
+
document.removeEventListener("visibilitychange", this.onVisibility);
|
|
848
|
+
}
|
|
849
|
+
this.onVisibility = null;
|
|
850
|
+
if (this.hiddenTimer) clearTimeout(this.hiddenTimer);
|
|
851
|
+
this.hiddenTimer = null;
|
|
852
|
+
this.closeFeed();
|
|
853
|
+
this.pending.clear();
|
|
854
|
+
this.shown.clear();
|
|
855
|
+
}
|
|
856
|
+
openFeed() {
|
|
857
|
+
if (this.es || !this.streamId) return;
|
|
858
|
+
const es = new EventSource(this.signaling.captionsUrl(this.streamId, this.opts.lang));
|
|
830
859
|
es.onmessage = (ev) => this.onFrame(ev);
|
|
831
860
|
es.onerror = () => this.emit("error", void 0);
|
|
832
861
|
this.es = es;
|
|
833
862
|
this.timer = setInterval(() => this.tick(), TICK_MS);
|
|
834
863
|
}
|
|
835
|
-
|
|
836
|
-
stop() {
|
|
864
|
+
closeFeed() {
|
|
837
865
|
this.es?.close();
|
|
838
866
|
this.es = null;
|
|
839
867
|
if (this.timer) clearInterval(this.timer);
|
|
840
868
|
this.timer = null;
|
|
841
|
-
|
|
842
|
-
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* Drop the feed while the page is hidden, restore it when it comes back.
|
|
872
|
+
*
|
|
873
|
+
* Nothing here is about rendering — a hidden tab shows no captions either
|
|
874
|
+
* way. It is about not holding a subscriber open, since that subscriber is
|
|
875
|
+
* what keeps a billed session alive on the engine.
|
|
876
|
+
*
|
|
877
|
+
* Buffered segments are deliberately kept across a suspend: they age out on
|
|
878
|
+
* their own (STALE_MS) and clearing them would blank the screen on return
|
|
879
|
+
* for no benefit.
|
|
880
|
+
*/
|
|
881
|
+
watchVisibility() {
|
|
882
|
+
if (typeof document === "undefined") return;
|
|
883
|
+
this.onVisibility = () => {
|
|
884
|
+
if (document.visibilityState === "hidden") {
|
|
885
|
+
if (this.hiddenTimer) return;
|
|
886
|
+
this.hiddenTimer = setTimeout(() => {
|
|
887
|
+
this.hiddenTimer = null;
|
|
888
|
+
this.closeFeed();
|
|
889
|
+
}, HIDDEN_GRACE_MS);
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
if (this.hiddenTimer) {
|
|
893
|
+
clearTimeout(this.hiddenTimer);
|
|
894
|
+
this.hiddenTimer = null;
|
|
895
|
+
}
|
|
896
|
+
this.openFeed();
|
|
897
|
+
};
|
|
898
|
+
document.addEventListener("visibilitychange", this.onVisibility);
|
|
843
899
|
}
|
|
844
900
|
onFrame(ev) {
|
|
845
901
|
let frame;
|
|
@@ -869,8 +925,9 @@ var MebiusCaptions = class extends TypedEmitter {
|
|
|
869
925
|
this.emit("cleared", { segmentId: id });
|
|
870
926
|
continue;
|
|
871
927
|
}
|
|
872
|
-
|
|
873
|
-
this.shown.
|
|
928
|
+
const rev = frame.rev ?? 0;
|
|
929
|
+
if (this.shown.get(id) === rev) continue;
|
|
930
|
+
this.shown.set(id, rev);
|
|
874
931
|
this.emit("segment", toSegment(id, frame, this.opts.lang));
|
|
875
932
|
}
|
|
876
933
|
}
|
|
@@ -883,6 +940,7 @@ function toSegment(segmentId, frame, lang) {
|
|
|
883
940
|
epochMs: frame.epochMs ?? 0,
|
|
884
941
|
durationMs: frame.durationMs ?? 0,
|
|
885
942
|
text: frame.text ?? "",
|
|
943
|
+
srcLang: frame.srcLang,
|
|
886
944
|
translation: frame.translations?.[lang],
|
|
887
945
|
machineGenerated: true
|
|
888
946
|
};
|