@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.cjs
CHANGED
|
@@ -852,6 +852,7 @@ function normalize(c, fallback) {
|
|
|
852
852
|
var TICK_MS = 100;
|
|
853
853
|
var STALE_MS = 5e3;
|
|
854
854
|
var MAX_QUEUE_MS = 1500;
|
|
855
|
+
var HIDDEN_GRACE_MS = 6e4;
|
|
855
856
|
var MebiusCaptions = class extends TypedEmitter {
|
|
856
857
|
/** @internal */
|
|
857
858
|
constructor(signaling, player, opts) {
|
|
@@ -862,26 +863,81 @@ var MebiusCaptions = class extends TypedEmitter {
|
|
|
862
863
|
this.es = null;
|
|
863
864
|
this.timer = null;
|
|
864
865
|
this.pending = /* @__PURE__ */ new Map();
|
|
865
|
-
|
|
866
|
+
/**
|
|
867
|
+
* segmentId -> the rev already handed to listeners. Not a Set: with interim
|
|
868
|
+
* revisions on, a segment stays pending while it is being corrected, and a
|
|
869
|
+
* plain "have I shown this id" check re-emits the same unchanged text on
|
|
870
|
+
* every 100ms tick. Comparing revs emits exactly once per actual revision.
|
|
871
|
+
*/
|
|
872
|
+
this.shown = /* @__PURE__ */ new Map();
|
|
873
|
+
/** Kept so the feed can be reopened after a hidden-tab suspend. */
|
|
874
|
+
this.streamId = null;
|
|
875
|
+
this.hiddenTimer = null;
|
|
876
|
+
this.onVisibility = null;
|
|
866
877
|
}
|
|
867
878
|
/** Open the SSE connection and begin emitting segments for `streamId`. */
|
|
868
879
|
start(streamId) {
|
|
869
880
|
if (this.es) return;
|
|
870
|
-
|
|
871
|
-
|
|
881
|
+
this.streamId = streamId;
|
|
882
|
+
this.openFeed();
|
|
883
|
+
this.watchVisibility();
|
|
884
|
+
}
|
|
885
|
+
/** Close the connection and drop all buffered segments. */
|
|
886
|
+
stop() {
|
|
887
|
+
this.streamId = null;
|
|
888
|
+
if (this.onVisibility && typeof document !== "undefined") {
|
|
889
|
+
document.removeEventListener("visibilitychange", this.onVisibility);
|
|
890
|
+
}
|
|
891
|
+
this.onVisibility = null;
|
|
892
|
+
if (this.hiddenTimer) clearTimeout(this.hiddenTimer);
|
|
893
|
+
this.hiddenTimer = null;
|
|
894
|
+
this.closeFeed();
|
|
895
|
+
this.pending.clear();
|
|
896
|
+
this.shown.clear();
|
|
897
|
+
}
|
|
898
|
+
openFeed() {
|
|
899
|
+
if (this.es || !this.streamId) return;
|
|
900
|
+
const es = new EventSource(this.signaling.captionsUrl(this.streamId, this.opts.lang));
|
|
872
901
|
es.onmessage = (ev) => this.onFrame(ev);
|
|
873
902
|
es.onerror = () => this.emit("error", void 0);
|
|
874
903
|
this.es = es;
|
|
875
904
|
this.timer = setInterval(() => this.tick(), TICK_MS);
|
|
876
905
|
}
|
|
877
|
-
|
|
878
|
-
stop() {
|
|
906
|
+
closeFeed() {
|
|
879
907
|
this.es?.close();
|
|
880
908
|
this.es = null;
|
|
881
909
|
if (this.timer) clearInterval(this.timer);
|
|
882
910
|
this.timer = null;
|
|
883
|
-
|
|
884
|
-
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Drop the feed while the page is hidden, restore it when it comes back.
|
|
914
|
+
*
|
|
915
|
+
* Nothing here is about rendering — a hidden tab shows no captions either
|
|
916
|
+
* way. It is about not holding a subscriber open, since that subscriber is
|
|
917
|
+
* what keeps a billed session alive on the engine.
|
|
918
|
+
*
|
|
919
|
+
* Buffered segments are deliberately kept across a suspend: they age out on
|
|
920
|
+
* their own (STALE_MS) and clearing them would blank the screen on return
|
|
921
|
+
* for no benefit.
|
|
922
|
+
*/
|
|
923
|
+
watchVisibility() {
|
|
924
|
+
if (typeof document === "undefined") return;
|
|
925
|
+
this.onVisibility = () => {
|
|
926
|
+
if (document.visibilityState === "hidden") {
|
|
927
|
+
if (this.hiddenTimer) return;
|
|
928
|
+
this.hiddenTimer = setTimeout(() => {
|
|
929
|
+
this.hiddenTimer = null;
|
|
930
|
+
this.closeFeed();
|
|
931
|
+
}, HIDDEN_GRACE_MS);
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
if (this.hiddenTimer) {
|
|
935
|
+
clearTimeout(this.hiddenTimer);
|
|
936
|
+
this.hiddenTimer = null;
|
|
937
|
+
}
|
|
938
|
+
this.openFeed();
|
|
939
|
+
};
|
|
940
|
+
document.addEventListener("visibilitychange", this.onVisibility);
|
|
885
941
|
}
|
|
886
942
|
onFrame(ev) {
|
|
887
943
|
let frame;
|
|
@@ -911,8 +967,9 @@ var MebiusCaptions = class extends TypedEmitter {
|
|
|
911
967
|
this.emit("cleared", { segmentId: id });
|
|
912
968
|
continue;
|
|
913
969
|
}
|
|
914
|
-
|
|
915
|
-
this.shown.
|
|
970
|
+
const rev = frame.rev ?? 0;
|
|
971
|
+
if (this.shown.get(id) === rev) continue;
|
|
972
|
+
this.shown.set(id, rev);
|
|
916
973
|
this.emit("segment", toSegment(id, frame, this.opts.lang));
|
|
917
974
|
}
|
|
918
975
|
}
|
|
@@ -925,6 +982,7 @@ function toSegment(segmentId, frame, lang) {
|
|
|
925
982
|
epochMs: frame.epochMs ?? 0,
|
|
926
983
|
durationMs: frame.durationMs ?? 0,
|
|
927
984
|
text: frame.text ?? "",
|
|
985
|
+
srcLang: frame.srcLang,
|
|
928
986
|
translation: frame.translations?.[lang],
|
|
929
987
|
machineGenerated: true
|
|
930
988
|
};
|